diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index e42ddc2e9..b1be4aa21 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -35,7 +35,7 @@ jobs: run: | echo "DEV_VERSION=$(./gradlew properties | awk '/^version:/ { print $2 }')" >> $GITHUB_ENV echo "RELEASE_VERSION=$(./gradlew properties -Prelease | awk '/^version:/ { print $2 }')" >> $GITHUB_ENV - - name: Gradle build on Ununtu + - name: Gradle build on Ubuntu if: matrix.os == 'ubuntu-latest' run: | ./gradlew build diff --git a/adminapi/src/main/java/io/minio/admin/AddServiceAccountResp.java b/adminapi/src/main/java/io/minio/admin/AddServiceAccountResponse.java similarity index 96% rename from adminapi/src/main/java/io/minio/admin/AddServiceAccountResp.java rename to adminapi/src/main/java/io/minio/admin/AddServiceAccountResponse.java index c48c6f606..4967709fd 100644 --- a/adminapi/src/main/java/io/minio/admin/AddServiceAccountResp.java +++ b/adminapi/src/main/java/io/minio/admin/AddServiceAccountResponse.java @@ -28,7 +28,7 @@ * "https://github.com/minio/madmin-go/blob/main/user-commands.go#L388">user-commands.go */ @JsonIgnoreProperties(ignoreUnknown = true) -public class AddServiceAccountResp { +public class AddServiceAccountResponse { @JsonProperty("credentials") private Credentials credentials; diff --git a/adminapi/src/main/java/io/minio/admin/GroupAddUpdateRemoveInfo.java b/adminapi/src/main/java/io/minio/admin/AddUpdateRemoveGroupArgs.java similarity index 81% rename from adminapi/src/main/java/io/minio/admin/GroupAddUpdateRemoveInfo.java rename to adminapi/src/main/java/io/minio/admin/AddUpdateRemoveGroupArgs.java index 039c5acda..709d502a3 100644 --- a/adminapi/src/main/java/io/minio/admin/GroupAddUpdateRemoveInfo.java +++ b/adminapi/src/main/java/io/minio/admin/AddUpdateRemoveGroupArgs.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; @@ -28,7 +27,8 @@ /** Represents groupAddUpdateRemove information. */ @JsonIgnoreProperties(ignoreUnknown = true) -public class GroupAddUpdateRemoveInfo { +@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") +public class AddUpdateRemoveGroupArgs { @JsonProperty("group") private String group; @@ -41,7 +41,7 @@ public class GroupAddUpdateRemoveInfo { @JsonProperty("isRemove") private boolean isRemove; - public GroupAddUpdateRemoveInfo( + public AddUpdateRemoveGroupArgs( @Nonnull @JsonProperty("group") String group, @Nullable @JsonProperty("groupStatus") Status groupStatus, @Nullable @JsonProperty("members") List members, @@ -51,20 +51,4 @@ public GroupAddUpdateRemoveInfo( this.members = (members != null) ? Collections.unmodifiableList(members) : null; this.isRemove = isRemove; } - - public String group() { - return group; - } - - public Status groupStatus() { - return groupStatus; - } - - public List members() { - return Collections.unmodifiableList(members == null ? new LinkedList<>() : members); - } - - public boolean isRemove() { - return isRemove; - } } diff --git a/adminapi/src/main/java/io/minio/admin/Crypto.java b/adminapi/src/main/java/io/minio/admin/Crypto.java index c42c51f32..8902e6d74 100644 --- a/adminapi/src/main/java/io/minio/admin/Crypto.java +++ b/adminapi/src/main/java/io/minio/admin/Crypto.java @@ -17,6 +17,7 @@ package io.minio.admin; +import io.minio.errors.MinioException; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; @@ -156,22 +157,25 @@ private static byte[] generateKey(byte[] secret, byte[] salt) { } private static byte[] generateEncryptDecryptAdditionalData( - boolean encryptFlag, int aeadId, byte[] key, byte[] paddedNonce) - throws InvalidCipherTextException { - AEADCipher cipher = getEncryptCipher(aeadId, key, paddedNonce); - int outputLength = cipher.getMac().length; - byte[] additionalData = new byte[outputLength]; - cipher.doFinal(additionalData, 0); - return appendBytes(new byte[] {0}, additionalData); + boolean encryptFlag, int aeadId, byte[] key, byte[] paddedNonce) throws MinioException { + try { + AEADCipher cipher = getEncryptCipher(aeadId, key, paddedNonce); + int outputLength = cipher.getMac().length; + byte[] additionalData = new byte[outputLength]; + cipher.doFinal(additionalData, 0); + return appendBytes(new byte[] {0}, additionalData); + } catch (InvalidCipherTextException e) { + throw new MinioException(e); + } } private static byte[] generateEncryptAdditionalData(int aeadId, byte[] key, byte[] paddedNonce) - throws InvalidCipherTextException { + throws MinioException { return generateEncryptDecryptAdditionalData(true, aeadId, key, paddedNonce); } private static byte[] generateDecryptAdditionalData(int aeadId, byte[] key, byte[] paddedNonce) - throws InvalidCipherTextException { + throws MinioException { return generateEncryptDecryptAdditionalData(false, aeadId, key, paddedNonce); } @@ -190,7 +194,7 @@ private static byte[] updateNonceId(byte[] nonce, int idx) { } /** Encrypt data payload. */ - public static byte[] encrypt(byte[] payload, String password) throws InvalidCipherTextException { + public static byte[] encrypt(byte[] payload, String password) throws MinioException { byte[] nonce = random(NONCE_LENGTH); byte[] salt = random(SALT_LENGTH); @@ -219,7 +223,11 @@ public static byte[] encrypt(byte[] payload, String password) throws InvalidCiph int outputLength = cipher.getOutputSize(chunk.length); byte[] encryptedData = new byte[outputLength]; int outputOffset = cipher.processBytes(chunk, 0, chunk.length, encryptedData, 0); - cipher.doFinal(encryptedData, outputOffset); + try { + cipher.doFinal(encryptedData, outputOffset); + } catch (InvalidCipherTextException e) { + throw new MinioException(e); + } result = appendBytes(result, encryptedData); @@ -243,20 +251,24 @@ public static class DecryptReader { private byte[] oneByte = null; private boolean eof = false; - public DecryptReader(InputStream inputStream, byte[] secret) - throws EOFException, IOException, InvalidCipherTextException { + public DecryptReader(InputStream inputStream, byte[] secret) throws MinioException { this.inputStream = inputStream; this.secret = secret; - readFully(this.inputStream, this.salt, true); - readFully(this.inputStream, this.aeadId, true); - readFully(this.inputStream, this.nonce, true); + try { + readFully(this.inputStream, this.salt, true); + readFully(this.inputStream, this.aeadId, true); + readFully(this.inputStream, this.nonce, true); + } catch (EOFException e) { + throw new MinioException(e); + } catch (IOException e) { + throw new MinioException(e); + } this.key = generateKey(this.secret, this.salt); byte[] paddedNonce = appendBytes(this.nonce, new byte[] {0, 0, 0, 0}); this.additionalData = generateDecryptAdditionalData(this.aeadId[0], this.key, paddedNonce); } - private byte[] decrypt(byte[] encryptedData, boolean lastChunk) - throws InvalidCipherTextException { + private byte[] decrypt(byte[] encryptedData, boolean lastChunk) throws MinioException { this.count++; if (lastChunk) { this.additionalData = markAsLast(this.additionalData); @@ -268,12 +280,16 @@ private byte[] decrypt(byte[] encryptedData, boolean lastChunk) byte[] decryptedData = new byte[outputLength]; int outputOffset = cipher.processBytes(encryptedData, 0, encryptedData.length, decryptedData, 0); - cipher.doFinal(decryptedData, outputOffset); + try { + cipher.doFinal(decryptedData, outputOffset); + } catch (InvalidCipherTextException e) { + throw new MinioException(e); + } return decryptedData; } /** Read a chunk at least one byte more than chunk size. */ - private byte[] readChunk() throws IOException { + private byte[] readChunk() throws EOFException, IOException { if (this.eof) { return new byte[] {}; } @@ -302,19 +318,24 @@ private byte[] readChunk() throws IOException { return baos.toByteArray(); } - public byte[] readAllBytes() throws IOException, InvalidCipherTextException { + public byte[] readAllBytes() throws MinioException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (!this.eof) { - byte[] payload = this.readChunk(); - baos.write(this.decrypt(payload, this.eof)); + try { + byte[] payload = this.readChunk(); + baos.write(this.decrypt(payload, this.eof)); + } catch (EOFException e) { + throw new MinioException(e); + } catch (IOException e) { + throw new MinioException(e); + } } return baos.toByteArray(); } } /** Decrypt data stream. */ - public static byte[] decrypt(InputStream inputStream, String password) - throws EOFException, IOException, InvalidCipherTextException { + public static byte[] decrypt(InputStream inputStream, String password) throws MinioException { DecryptReader reader = new DecryptReader(inputStream, password.getBytes(StandardCharsets.UTF_8)); return reader.readAllBytes(); diff --git a/adminapi/src/main/java/io/minio/admin/GetDataUsageInfoResponse.java b/adminapi/src/main/java/io/minio/admin/GetDataUsageInfoResponse.java new file mode 100644 index 000000000..0bf3a1b5f --- /dev/null +++ b/adminapi/src/main/java/io/minio/admin/GetDataUsageInfoResponse.java @@ -0,0 +1,255 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2022 MinIO, 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 io.minio.admin; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.Map; + +/** + * Represents data usage stats of the current object API. + * + * @see data-usage-utils.go + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class GetDataUsageInfoResponse { + @JsonProperty("lastUpdate") + private ZonedDateTime lastUpdate; + + @JsonProperty("objectsCount") + private long objectsCount; + + @JsonProperty("versionsCount") + private long versionsCount; + + @JsonProperty("objectsTotalSize") + private long objectsTotalSize; + + @JsonProperty("objectsReplicationInfo") + private Map objectsReplicationInfo; + + @JsonProperty("bucketsCount") + private long bucketsCount; + + @JsonProperty("bucketsUsageInfo") + private Map bucketsUsageInfo; + + @JsonProperty("bucketsSizes") + private Map bucketsSizes; + + @JsonProperty("tierStats") + private AllTierStats tierStats; + + public ZonedDateTime lastUpdate() { + return lastUpdate; + } + + public long objectsCount() { + return objectsCount; + } + + public long versionsCount() { + return versionsCount; + } + + public long objectsTotalSize() { + return objectsTotalSize; + } + + public Map objectsReplicationInfo() { + return Collections.unmodifiableMap(this.objectsReplicationInfo); + } + + public long bucketsCount() { + return bucketsCount; + } + + public Map bucketsUsageInfo() { + return Collections.unmodifiableMap(this.bucketsUsageInfo); + } + + public Map bucketsSizes() { + return Collections.unmodifiableMap(bucketsSizes); + } + + public AllTierStats tierStats() { + return tierStats; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class BucketTargetUsageInfo { + @JsonProperty("objectsPendingReplicationTotalSize") + private long objectsPendingReplicationTotalSize; + + @JsonProperty("objectsFailedReplicationTotalSize") + private long objectsFailedReplicationTotalSize; + + @JsonProperty("objectsReplicatedTotalSize") + private long objectsReplicatedTotalSize; + + @JsonProperty("objectReplicaTotalSize") + private long objectReplicaTotalSize; + + @JsonProperty("objectsPendingReplicationCount") + private long objectsPendingReplicationCount; + + @JsonProperty("objectsFailedReplicationCount") + private long objectsFailedReplicationCount; + + public long objectsPendingReplicationTotalSize() { + return objectsPendingReplicationTotalSize; + } + + public long objectsFailedReplicationTotalSize() { + return objectsFailedReplicationTotalSize; + } + + public long objectsReplicatedTotalSize() { + return objectsReplicatedTotalSize; + } + + public long objectReplicaTotalSize() { + return objectReplicaTotalSize; + } + + public long objectsPendingReplicationCount() { + return objectsPendingReplicationCount; + } + + public long objectsFailedReplicationCount() { + return objectsFailedReplicationCount; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class BucketUsageInfo { + @JsonProperty("size") + private long size; + + @JsonProperty("objectsPendingReplicationTotalSize") + private long objectsPendingReplicationTotalSize; + + @JsonProperty("objectsFailedReplicationTotalSize") + private long objectsFailedReplicationTotalSize; + + @JsonProperty("objectsReplicatedTotalSize") + private long objectsReplicatedTotalSize; + + @JsonProperty("objectsPendingReplicationCount") + private long objectsPendingReplicationCount; + + @JsonProperty("objectsFailedReplicationCount") + private long objectsFailedReplicationCount; + + @JsonProperty("objectsCount") + private long objectsCount; + + @JsonProperty("objectsSizesHistogram") + private Map objectsSizesHistogram; + + @JsonProperty("versionsCount") + private long versionsCount; + + @JsonProperty("objectReplicaTotalSize") + private long objectReplicaTotalSize; + + @JsonProperty("objectsReplicationInfo") + private Map objectsReplicationInfo; + + public long size() { + return size; + } + + public long objectsPendingReplicationTotalSize() { + return objectsPendingReplicationTotalSize; + } + + public long objectsFailedReplicationTotalSize() { + return objectsFailedReplicationTotalSize; + } + + public long objectsReplicatedTotalSize() { + return objectsReplicatedTotalSize; + } + + public long objectsPendingReplicationCount() { + return objectsPendingReplicationCount; + } + + public long objectsFailedReplicationCount() { + return objectsFailedReplicationCount; + } + + public long objectsCount() { + return objectsCount; + } + + public Map objectsSizesHistogram() { + return Collections.unmodifiableMap(this.objectsSizesHistogram); + } + + public long versionsCount() { + return versionsCount; + } + + public long objectReplicaTotalSize() { + return objectReplicaTotalSize; + } + + public Map objectsReplicationInfo() { + return Collections.unmodifiableMap(this.objectsReplicationInfo); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class TierStats { + @JsonProperty("TotalSize") + private long totalSize; + + @JsonProperty("NumVersions") + private int numVersions; + + @JsonProperty("NumObjects") + private int numObjects; + + public long totalSize() { + return totalSize; + } + + public int numVersions() { + return numVersions; + } + + public int numObjects() { + return numObjects; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class AllTierStats { + @JsonProperty("Tiers") + private Map tiers; + + public Map tiers() { + return Collections.unmodifiableMap(this.tiers); + } + } +} diff --git a/adminapi/src/main/java/io/minio/admin/GroupInfo.java b/adminapi/src/main/java/io/minio/admin/GetGroupInfoResponse.java similarity index 97% rename from adminapi/src/main/java/io/minio/admin/GroupInfo.java rename to adminapi/src/main/java/io/minio/admin/GetGroupInfoResponse.java index 3d53def2d..f137c746e 100644 --- a/adminapi/src/main/java/io/minio/admin/GroupInfo.java +++ b/adminapi/src/main/java/io/minio/admin/GetGroupInfoResponse.java @@ -25,7 +25,7 @@ /** Represents group information. */ @JsonIgnoreProperties(ignoreUnknown = true) -public class GroupInfo { +public class GetGroupInfoResponse { @JsonProperty("name") private String name; diff --git a/adminapi/src/main/java/io/minio/admin/GetServerInfoResponse.java b/adminapi/src/main/java/io/minio/admin/GetServerInfoResponse.java new file mode 100644 index 000000000..33984fbf4 --- /dev/null +++ b/adminapi/src/main/java/io/minio/admin/GetServerInfoResponse.java @@ -0,0 +1,868 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2022 MinIO, 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 io.minio.admin; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * InfoMessage container to hold server admin related information. + * + * @see heal-commands.go + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class GetServerInfoResponse { + @JsonProperty("mode") + private String mode; + + @JsonProperty("deploymentID") + private String deploymentID; + + @JsonProperty("buckets") + private Buckets buckets; + + @JsonProperty("objects") + private Objects objects; + + @JsonProperty("versions") + private Versions versions; + + @JsonProperty("usage") + private Usage usage; + + @JsonProperty("backend") + private Backend backend; + + @JsonProperty("servers") + private List servers; + + @JsonProperty("pools") + private Map> pools; + + public String mode() { + return mode; + } + + public String deploymentID() { + return deploymentID; + } + + public Buckets buckets() { + return buckets; + } + + public Objects objects() { + return objects; + } + + public Versions versions() { + return versions; + } + + public Usage usage() { + return usage; + } + + public Backend backend() { + return backend; + } + + public List servers() { + return Collections.unmodifiableList(servers == null ? new LinkedList<>() : servers); + } + + public Map> pools() { + return pools; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Buckets { + @JsonProperty("count") + private Integer count; + + @JsonProperty("error") + private String error; + + public Integer count() { + return count; + } + + public String error() { + return error; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Objects { + @JsonProperty("count") + private Integer count; + + @JsonProperty("error") + private String error; + + public Integer count() { + return count; + } + + public String error() { + return error; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Versions { + @JsonProperty("count") + private Integer count; + + @JsonProperty("error") + private String error; + + public Integer count() { + return count; + } + + public String error() { + return error; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Usage { + @JsonProperty("size") + private Long size; + + @JsonProperty("error") + private String error; + + public Long size() { + return size; + } + + public String error() { + return error; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Backend { + @JsonProperty("backendType") + private String backendType; + + @JsonProperty("onlineDisks") + private Integer onlineDisks; + + @JsonProperty("offlineDisks") + private Integer offlineDisks; + + @JsonProperty("standardSCParity") + private Integer standardSCParity; + + @JsonProperty("rrSCParity") + private Integer rrSCParity; + + @JsonProperty("totalSets") + private List totalSets; + + @JsonProperty("totalDrivesPerSet") + private List totalDrivesPerSet; + + public String backendType() { + return backendType; + } + + public Integer onlineDisks() { + return onlineDisks; + } + + public Integer offlineDisks() { + return offlineDisks; + } + + public Integer standardSCParity() { + return standardSCParity; + } + + public Integer rrSCParity() { + return rrSCParity; + } + + public List totalSets() { + return Collections.unmodifiableList(totalSets == null ? new LinkedList<>() : totalSets); + } + + public List totalDrivesPerSet() { + return Collections.unmodifiableList( + totalDrivesPerSet == null ? new LinkedList<>() : totalDrivesPerSet); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ServerProperties { + @JsonProperty("state") + private String state; + + @JsonProperty("endpoint") + private String endpoint; + + @JsonProperty("scheme") + private String scheme; + + @JsonProperty("uptime") + private Integer uptime; + + @JsonProperty("version") + private String version; + + @JsonProperty("commitID") + private String commitID; + + @JsonProperty("network") + private Map network; + + @JsonProperty("drives") + private List disks; + + @JsonProperty("poolNumber") + private Integer poolNumber; + + @JsonProperty("mem_stats") + private MemStats memStats; + + @JsonProperty("go_max_procs") + private Integer goMaxProcs; + + @JsonProperty("num_cpu") + private Integer numCPU; + + @JsonProperty("runtime_version") + private String runtimeVersion; + + @JsonProperty("gc_stats") + private GCStats gCStats; + + @JsonProperty("minio_env_vars") + private Map minioEnvVars; + + public String state() { + return state; + } + + public String endpoint() { + return endpoint; + } + + public String scheme() { + return scheme; + } + + public Integer uptime() { + return uptime; + } + + public String version() { + return version; + } + + public String commitID() { + return commitID; + } + + public Map network() { + return Collections.unmodifiableMap(this.network); + } + + public List disks() { + return Collections.unmodifiableList(disks == null ? new LinkedList<>() : disks); + } + + public Integer poolNumber() { + return poolNumber; + } + + public MemStats memStats() { + return memStats; + } + + public Integer goMaxProcs() { + return goMaxProcs; + } + + public Integer numCPU() { + return numCPU; + } + + public String runtimeVersion() { + return runtimeVersion; + } + + public GCStats gCStats() { + return gCStats; + } + + public Map minioEnvVars() { + return Collections.unmodifiableMap(this.minioEnvVars); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Disk { + @JsonProperty("endpoint") + private String endpoint; + + @JsonProperty("rootDisk") + private boolean rootDisk; + + @JsonProperty("path") + private String path; + + @JsonProperty("healing") + private boolean healing; + + @JsonProperty("scanning") + private boolean scanning; + + @JsonProperty("state") + private String state; + + @JsonProperty("uuid") + private String uuid; + + @JsonProperty("major") + private BigDecimal major; + + @JsonProperty("minor") + private BigDecimal minor; + + @JsonProperty("model") + private String model; + + @JsonProperty("totalspace") + private BigDecimal totalspace; + + @JsonProperty("usedspace") + private BigDecimal usedspace; + + @JsonProperty("availspace") + private BigDecimal availspace; + + @JsonProperty("readthroughput") + private BigDecimal readthroughput; + + @JsonProperty("writethroughput") + private BigDecimal writethroughput; + + @JsonProperty("readlatency") + private BigDecimal readlatency; + + @JsonProperty("writelatency") + private BigDecimal writelatency; + + @JsonProperty("utilization") + private BigDecimal utilization; + + @JsonProperty("metrics") + private DiskMetrics metrics; + + @JsonProperty("heal_info") + private HealingDisk healInfo; + + @JsonProperty("used_inodes") + private BigDecimal usedInodes; + + @JsonProperty("free_inodes") + private BigDecimal freeInodes; + + @JsonProperty("pool_index") + private Integer poolIndex; + + @JsonProperty("set_index") + private Integer setIndex; + + @JsonProperty("disk_index") + private Integer diskIndex; + + public String endpoint() { + return endpoint; + } + + public boolean isRootDisk() { + return rootDisk; + } + + public String path() { + return path; + } + + public boolean isHealing() { + return healing; + } + + public boolean isScanning() { + return scanning; + } + + public String state() { + return state; + } + + public String uuid() { + return uuid; + } + + public BigDecimal major() { + return major; + } + + public BigDecimal minor() { + return minor; + } + + public String model() { + return model; + } + + public BigDecimal totalspace() { + return totalspace; + } + + public BigDecimal usedspace() { + return usedspace; + } + + public BigDecimal availspace() { + return availspace; + } + + public BigDecimal readthroughput() { + return readthroughput; + } + + public BigDecimal writethroughput() { + return writethroughput; + } + + public BigDecimal readlatency() { + return readlatency; + } + + public BigDecimal writelatency() { + return writelatency; + } + + public BigDecimal utilization() { + return utilization; + } + + public DiskMetrics metrics() { + return metrics; + } + + public HealingDisk healInfo() { + return healInfo; + } + + public BigDecimal usedInodes() { + return usedInodes; + } + + public BigDecimal freeInodes() { + return freeInodes; + } + + public Integer poolIndex() { + return poolIndex; + } + + public Integer setIndex() { + return setIndex; + } + + public Integer diskIndex() { + return diskIndex; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MemStats { + @JsonProperty("Alloc") + private BigDecimal alloc; + + @JsonProperty("TotalAlloc") + private BigDecimal totalAlloc; + + @JsonProperty("Mallocs") + private BigDecimal mallocs; + + @JsonProperty("Frees") + private BigDecimal frees; + + @JsonProperty("HeapAlloc") + private BigDecimal heapAlloc; + + public BigDecimal alloc() { + return alloc; + } + + public BigDecimal totalAlloc() { + return totalAlloc; + } + + public BigDecimal mallocs() { + return mallocs; + } + + public BigDecimal frees() { + return frees; + } + + public BigDecimal heapAlloc() { + return heapAlloc; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class GCStats { + @JsonProperty("last_gc") + private String lastGC; + + @JsonProperty("num_gc") + private Integer numGC; + + @JsonProperty("pause_total") + private Long pauseTotal; + + @JsonProperty("pause") + private List pause; + + @JsonProperty("pause_end") + private List pauseEnd; + + public String lastGC() { + return lastGC; + } + + public Integer numGC() { + return numGC; + } + + public Long pauseTotal() { + return pauseTotal; + } + + public List pause() { + return Collections.unmodifiableList(pause == null ? new LinkedList<>() : pause); + } + + public List pauseEnd() { + return Collections.unmodifiableList(pauseEnd == null ? new LinkedList<>() : pauseEnd); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class DiskMetrics { + @JsonProperty("lastMinute") + private Map lastMinute; + + @JsonProperty("apiCalls") + private Map apiCalls; + + @JsonProperty("totalErrorsAvailability") + private Integer totalErrorsAvailability; + + @JsonProperty("totalErrorsTimeout") + private Integer totalErrorsTimeout; + + @JsonProperty("totalTokens") + private Long totalTokens; + + @JsonProperty("totalWaiting") + private Long totalWaiting; + + @JsonProperty("totalWrites") + private Long totalWrites; + + @JsonProperty("totalDeletes") + private Long totalDeletes; + + public Integer totalErrorsAvailability() { + return totalErrorsAvailability; + } + + public Integer totalErrorsTimeout() { + return totalErrorsTimeout; + } + + public Map lastMinute() { + return Collections.unmodifiableMap(lastMinute); + } + + public Map apiCalls() { + return Collections.unmodifiableMap(apiCalls); + } + + public Long totalTokens() { + return totalTokens; + } + + public Long totalWaiting() { + return totalWaiting; + } + + public Long totalWrites() { + return totalWrites; + } + + public Long totalDeletes() { + return totalDeletes; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class HealingDisk { + @JsonProperty("id") + private String id; + + @JsonProperty("heal_id") + private String healID; + + @JsonProperty("pool_index") + private Integer poolIndex; + + @JsonProperty("set_index") + private Integer setIndex; + + @JsonProperty("disk_index") + private Integer diskIndex; + + @JsonProperty("endpoint") + private String endpoint; + + @JsonProperty("path") + private String path; + + @JsonProperty("started") + private String started; + + @JsonProperty("last_update") + private String lastUpdate; + + @JsonProperty("objects_total_count") + private BigDecimal objectsTotalCount; + + @JsonProperty("objects_total_size") + private BigDecimal objectsTotalSize; + + @JsonProperty("items_healed") + private BigDecimal itemsHealed; + + @JsonProperty("items_failed") + private BigDecimal itemsFailed; + + @JsonProperty("bytes_done") + private BigDecimal bytesDone; + + @JsonProperty("bytes_failed") + private BigDecimal bytesFailed; + + @JsonProperty("objects_healed") + private BigDecimal objectsHealed; + + @JsonProperty("objects_failed") + private BigDecimal objectsFailed; + + @JsonProperty("current_bucket") + private String bucket; + + @JsonProperty("current_object") + private String object; + + @JsonProperty("queued_buckets") + private List queuedBuckets; + + @JsonProperty("healed_buckets") + private List healedBuckets; + + public String id() { + return id; + } + + public String healID() { + return healID; + } + + public Integer poolIndex() { + return poolIndex; + } + + public Integer setIndex() { + return setIndex; + } + + public Integer diskIndex() { + return diskIndex; + } + + public String endpoint() { + return endpoint; + } + + public String path() { + return path; + } + + public String started() { + return started; + } + + public String lastUpdate() { + return lastUpdate; + } + + public BigDecimal objectsTotalCount() { + return objectsTotalCount; + } + + public BigDecimal objectsTotalSize() { + return objectsTotalSize; + } + + public BigDecimal itemsHealed() { + return itemsHealed; + } + + public BigDecimal itemsFailed() { + return itemsFailed; + } + + public BigDecimal bytesDone() { + return bytesDone; + } + + public BigDecimal bytesFailed() { + return bytesFailed; + } + + public BigDecimal objectsHealed() { + return objectsHealed; + } + + public BigDecimal objectsFailed() { + return objectsFailed; + } + + public String bucket() { + return bucket; + } + + public String object() { + return object; + } + + public List queuedBuckets() { + return Collections.unmodifiableList( + queuedBuckets == null ? new LinkedList<>() : queuedBuckets); + } + + public List healedBuckets() { + return Collections.unmodifiableList( + healedBuckets == null ? new LinkedList<>() : healedBuckets); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class TimedAction { + @JsonProperty("count") + private BigDecimal count; + + @JsonProperty("acc_time_ns") + private BigDecimal accTime; + + @JsonProperty("bytes") + private BigDecimal bytes; + + public BigDecimal count() { + return count; + } + + public BigDecimal accTime() { + return accTime; + } + + public BigDecimal bytes() { + return bytes; + } + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ErasureSetInfo { + @JsonProperty("id") + private Integer id; + + @JsonProperty("rawUsage") + private BigDecimal rawUsage; + + @JsonProperty("rawCapacity") + private BigDecimal rawCapacity; + + @JsonProperty("usage") + private BigDecimal usage; + + @JsonProperty("objectsCount") + private BigDecimal objectsCount; + + @JsonProperty("versionsCount") + private BigDecimal versionsCount; + + @JsonProperty("healDisks") + private Integer healDisks; + + public Integer id() { + return id; + } + + public BigDecimal rawUsage() { + return rawUsage; + } + + public BigDecimal rawCapacity() { + return rawCapacity; + } + + public BigDecimal usage() { + return usage; + } + + public BigDecimal objectsCount() { + return objectsCount; + } + + public BigDecimal versionsCount() { + return versionsCount; + } + + public Integer healDisks() { + return healDisks; + } + } +} diff --git a/adminapi/src/main/java/io/minio/admin/GetServiceAccountInfoResp.java b/adminapi/src/main/java/io/minio/admin/GetServiceAccountInfoResponse.java similarity index 97% rename from adminapi/src/main/java/io/minio/admin/GetServiceAccountInfoResp.java rename to adminapi/src/main/java/io/minio/admin/GetServiceAccountInfoResponse.java index 1694bf113..c93f86cbb 100644 --- a/adminapi/src/main/java/io/minio/admin/GetServiceAccountInfoResp.java +++ b/adminapi/src/main/java/io/minio/admin/GetServiceAccountInfoResponse.java @@ -27,7 +27,7 @@ * "https://github.com/minio/madmin-go/blob/main/user-commands.go#L535">user-commands.go */ @JsonIgnoreProperties(ignoreUnknown = true) -public class GetServiceAccountInfoResp { +public class GetServiceAccountInfoResponse { @JsonProperty("parentUser") private String parentUser; diff --git a/adminapi/src/main/java/io/minio/admin/ListServiceAccountResp.java b/adminapi/src/main/java/io/minio/admin/ListServiceAccountResponse.java similarity index 98% rename from adminapi/src/main/java/io/minio/admin/ListServiceAccountResp.java rename to adminapi/src/main/java/io/minio/admin/ListServiceAccountResponse.java index baa7c12a6..f6fa095b5 100644 --- a/adminapi/src/main/java/io/minio/admin/ListServiceAccountResp.java +++ b/adminapi/src/main/java/io/minio/admin/ListServiceAccountResponse.java @@ -25,7 +25,7 @@ /** list service account response. */ @JsonIgnoreProperties(ignoreUnknown = true) -public class ListServiceAccountResp { +public class ListServiceAccountResponse { @JsonProperty("accounts") private List accounts; diff --git a/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java b/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java index de11bd275..66ef4a994 100644 --- a/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java +++ b/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java @@ -17,6 +17,7 @@ package io.minio.admin; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -27,27 +28,21 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.minio.Digest; -import io.minio.MinioProperties; -import io.minio.S3Escaper; +import io.minio.Checksum; +import io.minio.Http; import io.minio.Signer; import io.minio.Time; -import io.minio.admin.messages.DataUsageInfo; -import io.minio.admin.messages.info.Message; +import io.minio.Utils; import io.minio.credentials.Credentials; import io.minio.credentials.Provider; import io.minio.credentials.StaticProvider; -import io.minio.http.HttpUtils; -import io.minio.http.Method; +import io.minio.errors.MinioException; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.HashMap; @@ -65,7 +60,6 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -import org.bouncycastle.crypto.InvalidCipherTextException; /** Client to perform MinIO administration operations. */ public class MinioAdminClient { @@ -89,7 +83,9 @@ private enum Command { UPDATE_SERVICE_ACCOUNT("update-service-account"), LIST_SERVICE_ACCOUNTS("list-service-accounts"), DELETE_SERVICE_ACCOUNT("delete-service-account"), - INFO_SERVICE_ACCOUNT("info-service-account"); + INFO_SERVICE_ACCOUNT("info-service-account"), + IDP_BUILTIN_POLICY_ATTACH("idp/builtin/policy/attach"), + IDP_BUILTIN_POLICY_DETACH("idp/builtin/policy/detach"); private final String value; private Command(String value) { @@ -115,7 +111,7 @@ public String toString() { OBJECT_MAPPER.registerModule(new JavaTimeModule()); } - private String userAgent = MinioProperties.INSTANCE.getDefaultUserAgent(); + private String userAgent = Utils.getDefaultUserAgent(); private PrintWriter traceStream; private HttpUrl baseUrl; @@ -137,41 +133,42 @@ private Credentials getCredentials() { return creds; } - private Response execute( - Method method, Command command, Multimap queryParamMap, byte[] body) - throws InvalidKeyException, IOException, NoSuchAlgorithmException { + private Response httpExecute( + Http.Method method, Command command, Multimap queryParamMap, byte[] body) + throws IOException, MinioException { Credentials creds = getCredentials(); HttpUrl.Builder urlBuilder = this.baseUrl .newBuilder() .host(this.baseUrl.host()) - .addEncodedPathSegments(S3Escaper.encodePath("minio/admin/v3/" + command.toString())); + .addEncodedPathSegments(Utils.encodePath("minio/admin/v3/" + command.toString())); if (queryParamMap != null) { for (Map.Entry entry : queryParamMap.entries()) { urlBuilder.addEncodedQueryParameter( - S3Escaper.encode(entry.getKey()), S3Escaper.encode(entry.getValue())); + Utils.encode(entry.getKey()), Utils.encode(entry.getValue())); } } HttpUrl url = urlBuilder.build(); Request.Builder requestBuilder = new Request.Builder(); requestBuilder.url(url); - requestBuilder.header("Host", HttpUtils.getHostHeader(url)); + requestBuilder.header("Host", Utils.getHostHeader(url)); requestBuilder.header("Accept-Encoding", "identity"); // Disable default gzip compression. requestBuilder.header("User-Agent", this.userAgent); requestBuilder.header("x-amz-date", ZonedDateTime.now().format(Time.AMZ_DATE_FORMAT)); if (creds.sessionToken() != null) { requestBuilder.header("X-Amz-Security-Token", creds.sessionToken()); } - if (body == null && (method != Method.GET && method != Method.HEAD)) { - body = HttpUtils.EMPTY_BODY; + if (body == null && (method != Http.Method.GET && method != Http.Method.HEAD)) { + body = Utils.EMPTY_BODY; } if (body != null) { - requestBuilder.header("x-amz-content-sha256", Digest.sha256Hash(body, body.length)); + requestBuilder.header( + "x-amz-content-sha256", Checksum.hexString(Checksum.SHA256.sum(body, 0, body.length))); requestBuilder.method(method.toString(), RequestBody.create(body, DEFAULT_MEDIA_TYPE)); } else { - requestBuilder.header("x-amz-content-sha256", Digest.ZERO_SHA256_HASH); + requestBuilder.header("x-amz-content-sha256", Checksum.ZERO_SHA256_HASH); } Request request = requestBuilder.build(); @@ -222,6 +219,16 @@ private Response execute( throw new RuntimeException("Request failed with response: " + response.body().string()); } + private Response execute( + Http.Method method, Command command, Multimap queryParamMap, byte[] body) + throws MinioException { + try { + return httpExecute(method, command, queryParamMap, body); + } catch (IOException e) { + throw new MinioException(e); + } + } + /** * Adds a user with the specified access and secret key. * @@ -230,19 +237,15 @@ private Response execute( * @param secretKey Secret key. * @param policyName Policy name. * @param memberOf List of group. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. - * @throws InvalidCipherTextException thrown to indicate data cannot be encrypted/decrypted. + * @throws MinioException thrown to indicate SDK exception. */ public void addUser( @Nonnull String accessKey, - @Nonnull UserInfo.Status status, + @Nonnull Status status, @Nullable String secretKey, @Nullable String policyName, @Nullable List memberOf) - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - InvalidCipherTextException { + throws MinioException { if (accessKey == null || accessKey.isEmpty()) { throw new IllegalArgumentException("access key must be provided"); } @@ -251,10 +254,13 @@ public void addUser( Credentials creds = getCredentials(); try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_USER, ImmutableMultimap.of("accessKey", accessKey), - Crypto.encrypt(OBJECT_MAPPER.writeValueAsBytes(userInfo), creds.secretKey()))) {} + Crypto.encrypt(OBJECT_MAPPER.writeValueAsBytes(userInfo), creds.secretKey()))) { + } catch (JsonProcessingException e) { + throw new MinioException(e); + } } /** @@ -262,17 +268,19 @@ public void addUser( * * @param accessKey Access Key. * @return {@link UserInfo} - user info for the specified accessKey. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public UserInfo getUserInfo(String accessKey) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public UserInfo getUserInfo(String accessKey) throws MinioException { try (Response response = execute( - Method.GET, Command.USER_INFO, ImmutableMultimap.of("accessKey", accessKey), null)) { + Http.Method.GET, + Command.USER_INFO, + ImmutableMultimap.of("accessKey", accessKey), + null)) { byte[] jsonData = response.body().bytes(); return OBJECT_MAPPER.readValue(jsonData, UserInfo.class); + } catch (IOException e) { + throw new MinioException(e); } } @@ -280,22 +288,21 @@ public UserInfo getUserInfo(String accessKey) * Obtains a list of all MinIO users. * * @return {@link Map} - List of all users. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. - * @throws InvalidCipherTextException thrown to indicate data cannot be encrypted/decrypted. + * @throws MinioException thrown to indicate SDK exception. */ - public Map listUsers() - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - InvalidCipherTextException { - try (Response response = execute(Method.GET, Command.LIST_USERS, null, null)) { + public Map listUsers() throws MinioException { + try (Response response = execute(Http.Method.GET, Command.LIST_USERS, null, null)) { Credentials creds = getCredentials(); byte[] jsonData = Crypto.decrypt(response.body().byteStream(), creds.secretKey()); MapType mapType = OBJECT_MAPPER .getTypeFactory() .constructMapType(HashMap.class, String.class, UserInfo.class); - return OBJECT_MAPPER.readValue(jsonData, mapType); + try { + return OBJECT_MAPPER.readValue(jsonData, mapType); + } catch (IOException e) { + throw new MinioException(e); + } } } @@ -303,19 +310,16 @@ public Map listUsers() * Deletes a user by it's access key * * @param accessKey Access Key. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public void deleteUser(@Nonnull String accessKey) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public void deleteUser(@Nonnull String accessKey) throws MinioException { if (accessKey == null || accessKey.isEmpty()) { throw new IllegalArgumentException("access key must be provided"); } try (Response response = execute( - Method.DELETE, + Http.Method.DELETE, Command.REMOVE_USER, ImmutableMultimap.of("accessKey", accessKey), null)) {} @@ -327,42 +331,42 @@ public void deleteUser(@Nonnull String accessKey) * @param group Group name. * @param groupStatus Status. * @param members Members of group. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ public void addUpdateGroup( @Nonnull String group, @Nullable Status groupStatus, @Nullable List members) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + throws MinioException { if (group == null || group.isEmpty()) { throw new IllegalArgumentException("group must be provided"); } - GroupAddUpdateRemoveInfo groupAddUpdateRemoveInfo = - new GroupAddUpdateRemoveInfo(group, groupStatus, members, false); + AddUpdateRemoveGroupArgs args = + new AddUpdateRemoveGroupArgs(group, groupStatus, members, false); try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_UPDATE_REMOVE_GROUP, null, - OBJECT_MAPPER.writeValueAsBytes(groupAddUpdateRemoveInfo))) {} + OBJECT_MAPPER.writeValueAsBytes(args))) { + } catch (JsonProcessingException e) { + throw new MinioException(e); + } } /** * Obtains group info for a specified MinIO group. * * @param group Group name. - * @return {@link GroupInfo} - group info for the specified group. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @return {@link GetGroupInfoResponse} - group info for the specified group. + * @throws MinioException thrown to indicate SDK exception. */ - public GroupInfo getGroupInfo(String group) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public GetGroupInfoResponse getGroupInfo(String group) throws MinioException { try (Response response = - execute(Method.GET, Command.GROUP_INFO, ImmutableMultimap.of("group", group), null)) { + execute(Http.Method.GET, Command.GROUP_INFO, ImmutableMultimap.of("group", group), null)) { byte[] jsonData = response.body().bytes(); - return OBJECT_MAPPER.readValue(jsonData, GroupInfo.class); + return OBJECT_MAPPER.readValue(jsonData, GetGroupInfoResponse.class); + } catch (IOException e) { + throw new MinioException(e); } } @@ -370,17 +374,16 @@ public GroupInfo getGroupInfo(String group) * Obtains a list of all MinIO groups. * * @return {@link List} - List of all groups. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public List listGroups() - throws NoSuchAlgorithmException, InvalidKeyException, IOException { - try (Response response = execute(Method.GET, Command.LIST_GROUPS, null, null)) { + public List listGroups() throws MinioException { + try (Response response = execute(Http.Method.GET, Command.LIST_GROUPS, null, null)) { byte[] jsonData = response.body().bytes(); CollectionType mapType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, String.class); return OBJECT_MAPPER.readValue(jsonData, mapType); + } catch (IOException e) { + throw new MinioException(e); } } @@ -388,24 +391,23 @@ public List listGroups() * Removes a group. * * @param group Group name. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public void removeGroup(@Nonnull String group) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public void removeGroup(@Nonnull String group) throws MinioException { if (group == null || group.isEmpty()) { throw new IllegalArgumentException("group must be provided"); } - GroupAddUpdateRemoveInfo groupAddUpdateRemoveInfo = - new GroupAddUpdateRemoveInfo(group, null, null, true); + AddUpdateRemoveGroupArgs args = new AddUpdateRemoveGroupArgs(group, null, null, true); try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_UPDATE_REMOVE_GROUP, null, - OBJECT_MAPPER.writeValueAsBytes(groupAddUpdateRemoveInfo))) {} + OBJECT_MAPPER.writeValueAsBytes(args))) { + } catch (JsonProcessingException e) { + throw new MinioException(e); + } } /** @@ -414,23 +416,22 @@ public void removeGroup(@Nonnull String group) * @param bucketName bucketName * @param size the capacity of the bucket * @param unit the quota unit of the size argument - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ public void setBucketQuota(@Nonnull String bucketName, long size, @Nonnull QuotaUnit unit) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { + throws MinioException { Map quotaEntity = new HashMap<>(); - if (size > 0) { - quotaEntity.put("quotatype", "hard"); - } + if (size > 0) quotaEntity.put("quotatype", "hard"); quotaEntity.put("quota", unit.toBytes(size)); try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.SET_BUCKET_QUOTA, ImmutableMultimap.of("bucket", bucketName), - OBJECT_MAPPER.writeValueAsBytes(quotaEntity))) {} + OBJECT_MAPPER.writeValueAsBytes(quotaEntity))) { + } catch (JsonProcessingException e) { + throw new MinioException(e); + } } /** @@ -438,15 +439,12 @@ public void setBucketQuota(@Nonnull String bucketName, long size, @Nonnull Quota * * @param bucketName bucketName * @return bytes of bucket - * @throws IOException - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException + * @throws MinioException thrown to indicate SDK exception. */ - public long getBucketQuota(String bucketName) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { + public long getBucketQuota(String bucketName) throws MinioException { try (Response response = execute( - Method.GET, + Http.Method.GET, Command.GET_BUCKET_QUOTA, ImmutableMultimap.of("bucket", bucketName), null)) { @@ -460,6 +458,8 @@ public long getBucketQuota(String bucketName) .findFirst() .map(entry -> Long.valueOf(entry.getValue().toString())) .orElseThrow(() -> new IllegalArgumentException("found not quota")); + } catch (IOException e) { + throw new MinioException(e); } } @@ -467,12 +467,9 @@ public long getBucketQuota(String bucketName) * Reset bucket quota * * @param bucketName bucketName - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public void clearBucketQuota(@Nonnull String bucketName) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { + public void clearBucketQuota(@Nonnull String bucketName) throws MinioException { setBucketQuota(bucketName, 0, QuotaUnit.KB); } @@ -498,12 +495,9 @@ public void clearBucketQuota(@Nonnull String bucketName) * * @param name Policy name. * @param policy Policy as JSON string. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public void addCannedPolicy(@Nonnull String name, @Nonnull String policy) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public void addCannedPolicy(@Nonnull String name, @Nonnull String policy) throws MinioException { if (name == null || name.isEmpty()) { throw new IllegalArgumentException("name must be provided"); } @@ -513,7 +507,7 @@ public void addCannedPolicy(@Nonnull String name, @Nonnull String policy) try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_CANNED_POLICY, ImmutableMultimap.of("name", name), policy.getBytes(StandardCharsets.UTF_8))) {} @@ -525,13 +519,11 @@ public void addCannedPolicy(@Nonnull String name, @Nonnull String policy) * @param userOrGroupName User/Group name. * @param isGroup Flag to denote userOrGroupName is a group name. * @param policyName Policy name or comma separated policy names. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ public void setPolicy( @Nonnull String userOrGroupName, boolean isGroup, @Nonnull String policyName) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + throws MinioException { if (userOrGroupName == null || userOrGroupName.isEmpty()) { throw new IllegalArgumentException("user/group name must be provided"); } @@ -541,7 +533,7 @@ public void setPolicy( try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.SET_USER_OR_GROUP_POLICY, ImmutableMultimap.of( "userOrGroup", @@ -558,13 +550,10 @@ public void setPolicy( * * @return {@link Map} - Map of policies, keyed by their name, with their actual * policy as their value. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public Map listCannedPolicies() - throws NoSuchAlgorithmException, InvalidKeyException, IOException { - try (Response response = execute(Method.GET, Command.LIST_CANNED_POLICIES, null, null)) { + public Map listCannedPolicies() throws MinioException { + try (Response response = execute(Http.Method.GET, Command.LIST_CANNED_POLICIES, null, null)) { MapType mapType = OBJECT_MAPPER .getTypeFactory() @@ -574,6 +563,8 @@ public Map listCannedPolicies() .>readValue(response.body().bytes(), mapType) .forEach((key, value) -> policies.put(key, value.toString())); return policies; + } catch (IOException e) { + throw new MinioException(e); } } @@ -581,19 +572,16 @@ public Map listCannedPolicies() * Removes canned policy by name. * * @param name Policy name. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public void removeCannedPolicy(@Nonnull String name) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public void removeCannedPolicy(@Nonnull String name) throws MinioException { if (name == null || name.isEmpty()) { throw new IllegalArgumentException("name must be provided"); } try (Response response = execute( - Method.DELETE, + Http.Method.DELETE, Command.REMOVE_CANNED_POLICY, ImmutableMultimap.of("name", name), null)) {} @@ -602,29 +590,28 @@ public void removeCannedPolicy(@Nonnull String name) /** * Get server/cluster data usage info * - * @return {@link DataUsageInfo} - DataUsageInfo object - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @return {@link GetDataUsageInfoResponse} + * @throws MinioException thrown to indicate SDK exception. */ - public DataUsageInfo getDataUsageInfo() - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try (Response response = execute(Method.GET, Command.DATA_USAGE_INFO, null, null)) { - return OBJECT_MAPPER.readValue(response.body().bytes(), DataUsageInfo.class); + public GetDataUsageInfoResponse getDataUsageInfo() throws MinioException { + try (Response response = execute(Http.Method.GET, Command.DATA_USAGE_INFO, null, null)) { + return OBJECT_MAPPER.readValue(response.body().bytes(), GetDataUsageInfoResponse.class); + } catch (IOException e) { + throw new MinioException(e); } } /** * Obtains admin info for the Minio server. * - * @return {@link Message} - admin info for the Minio server. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @return {@link GetServerInfoResponse} + * @throws MinioException thrown to indicate SDK exception. */ - public Message getServerInfo() throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try (Response response = execute(Method.GET, Command.INFO, null, null)) { - return OBJECT_MAPPER.readValue(response.body().charStream(), Message.class); + public GetServerInfoResponse getServerInfo() throws MinioException { + try (Response response = execute(Http.Method.GET, Command.INFO, null, null)) { + return OBJECT_MAPPER.readValue(response.body().charStream(), GetServerInfoResponse.class); + } catch (IOException e) { + throw new MinioException(e); } } @@ -639,10 +626,7 @@ public Message getServerInfo() throws IOException, NoSuchAlgorithmException, Inv * @param description Description for this access key. * @param expiration Expiry time. * @return {@link Credentials} - Service account info for the specified accessKey. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. - * @throws InvalidCipherTextException thrown to indicate data cannot be encrypted/decrypted. + * @throws MinioException thrown to indicate SDK exception. */ public Credentials addServiceAccount( @Nonnull String accessKey, @@ -652,8 +636,7 @@ public Credentials addServiceAccount( @Nullable String name, @Nullable String description, @Nullable ZonedDateTime expiration) - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - InvalidCipherTextException { + throws MinioException { if (accessKey == null || accessKey.isEmpty()) { throw new IllegalArgumentException("access key must be provided"); } @@ -675,28 +658,28 @@ public Credentials addServiceAccount( if (targetUser != null && !targetUser.isEmpty()) { serviceAccount.put("targetUser", targetUser); } - if (policy != null && !policy.isEmpty()) { - serviceAccount.put("policy", policy); - } - if (name != null && !name.isEmpty()) { - serviceAccount.put("name", name); - } + if (policy != null && !policy.isEmpty()) serviceAccount.put("policy", policy); + if (name != null && !name.isEmpty()) serviceAccount.put("name", name); if (description != null && !description.isEmpty()) { serviceAccount.put("description", description); } if (expiration != null) { - serviceAccount.put("expiration", expiration.format(Time.EXPIRATION_DATE_FORMAT)); + serviceAccount.put("expiration", expiration.format(Time.ISO8601UTC_FORMAT)); } Credentials creds = getCredentials(); try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_SERVICE_ACCOUNT, null, Crypto.encrypt(OBJECT_MAPPER.writeValueAsBytes(serviceAccount), creds.secretKey()))) { byte[] jsonData = Crypto.decrypt(response.body().byteStream(), creds.secretKey()); - return OBJECT_MAPPER.readValue(jsonData, AddServiceAccountResp.class).credentials(); + return OBJECT_MAPPER.readValue(jsonData, AddServiceAccountResponse.class).credentials(); + } catch (JsonProcessingException e) { + throw new MinioException(e); + } catch (IOException e) { + throw new MinioException(e); } } @@ -710,10 +693,7 @@ public Credentials addServiceAccount( * @param newName New service account name. * @param newDescription New description. * @param newExpiration New expiry time. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. - * @throws InvalidCipherTextException thrown to indicate data cannot be encrypted/decrypted. + * @throws MinioException thrown to indicate SDK exception. */ public void updateServiceAccount( @Nonnull String accessKey, @@ -723,8 +703,7 @@ public void updateServiceAccount( @Nullable String newName, @Nullable String newDescription, @Nullable ZonedDateTime newExpiration) - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - InvalidCipherTextException { + throws MinioException { if (accessKey == null || accessKey.isEmpty()) { throw new IllegalArgumentException("access key must be provided"); } @@ -741,46 +720,42 @@ public void updateServiceAccount( if (newSecretKey != null && !newSecretKey.isEmpty()) { serviceAccount.put("newSecretKey", newSecretKey); } - if (newPolicy != null && !newPolicy.isEmpty()) { - serviceAccount.put("newPolicy", newPolicy); - } + if (newPolicy != null && !newPolicy.isEmpty()) serviceAccount.put("newPolicy", newPolicy); serviceAccount.put("newStatus", newStatus ? "on" : "off"); - if (newName != null && !newName.isEmpty()) { - serviceAccount.put("newName", newName); - } + if (newName != null && !newName.isEmpty()) serviceAccount.put("newName", newName); if (newDescription != null && !newDescription.isEmpty()) { serviceAccount.put("newDescription", newDescription); } if (newExpiration != null) { - serviceAccount.put("newExpiration", newExpiration.format(Time.EXPIRATION_DATE_FORMAT)); + serviceAccount.put("newExpiration", newExpiration.format(Time.ISO8601UTC_FORMAT)); } Credentials creds = getCredentials(); try (Response response = execute( - Method.POST, + Http.Method.POST, Command.UPDATE_SERVICE_ACCOUNT, ImmutableMultimap.of("accessKey", accessKey), - Crypto.encrypt(OBJECT_MAPPER.writeValueAsBytes(serviceAccount), creds.secretKey()))) {} + Crypto.encrypt(OBJECT_MAPPER.writeValueAsBytes(serviceAccount), creds.secretKey()))) { + } catch (JsonProcessingException e) { + throw new MinioException(e); + } } /** * Deletes a service account by it's access key * * @param accessKey Access Key. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. + * @throws MinioException thrown to indicate SDK exception. */ - public void deleteServiceAccount(@Nonnull String accessKey) - throws NoSuchAlgorithmException, InvalidKeyException, IOException { + public void deleteServiceAccount(@Nonnull String accessKey) throws MinioException { if (accessKey == null || accessKey.isEmpty()) { throw new IllegalArgumentException("access key must be provided"); } try (Response response = execute( - Method.DELETE, + Http.Method.DELETE, Command.DELETE_SERVICE_ACCOUNT, ImmutableMultimap.of("accessKey", accessKey), null)) {} @@ -790,28 +765,26 @@ public void deleteServiceAccount(@Nonnull String accessKey) * Obtains a list of minio service account by user name. * * @param username user name. - * @return {@link ListServiceAccountResp} - List of minio service account. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. - * @throws InvalidCipherTextException thrown to indicate data cannot be encrypted/decrypted. + * @return {@link ListServiceAccountResponse} - List of minio service account. + * @throws MinioException thrown to indicate SDK exception. */ - public ListServiceAccountResp listServiceAccount(@Nonnull String username) - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - InvalidCipherTextException { + public ListServiceAccountResponse listServiceAccount(@Nonnull String username) + throws MinioException { if (username == null || username.isEmpty()) { throw new IllegalArgumentException("user name must be provided"); } try (Response response = execute( - Method.GET, + Http.Method.GET, Command.LIST_SERVICE_ACCOUNTS, ImmutableMultimap.of("user", username), null)) { Credentials creds = getCredentials(); byte[] jsonData = Crypto.decrypt(response.body().byteStream(), creds.secretKey()); - return OBJECT_MAPPER.readValue(jsonData, ListServiceAccountResp.class); + return OBJECT_MAPPER.readValue(jsonData, ListServiceAccountResponse.class); + } catch (IOException e) { + throw new MinioException(e); } } @@ -819,30 +792,78 @@ public ListServiceAccountResp listServiceAccount(@Nonnull String username) * Obtains service account info for a specified MinIO user. * * @param accessKey Access Key. - * @return {@link GetServiceAccountInfoResp} - Service account info for the specified accessKey. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on MinIO REST operation. - * @throws InvalidCipherTextException thrown to indicate data cannot be encrypted/decrypted. + * @return {@link GetServiceAccountInfoResponse} - Service account info for the specified + * accessKey. + * @throws MinioException thrown to indicate SDK exception. */ - public GetServiceAccountInfoResp getServiceAccountInfo(@Nonnull String accessKey) - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - InvalidCipherTextException { + public GetServiceAccountInfoResponse getServiceAccountInfo(@Nonnull String accessKey) + throws MinioException { if (accessKey == null || accessKey.isEmpty()) { throw new IllegalArgumentException("access key must be provided"); } try (Response response = execute( - Method.GET, + Http.Method.GET, Command.INFO_SERVICE_ACCOUNT, ImmutableMultimap.of("accessKey", accessKey), null)) { Credentials creds = getCredentials(); byte[] jsonData = Crypto.decrypt(response.body().byteStream(), creds.secretKey()); - return OBJECT_MAPPER.readValue(jsonData, GetServiceAccountInfoResp.class); + return OBJECT_MAPPER.readValue(jsonData, GetServiceAccountInfoResponse.class); + } catch (IOException e) { + throw new MinioException(e); + } + } + + private PolicyAssociationResponse attachDetachPolicy( + @Nonnull Command command, + @Nonnull String[] polices, + @Nullable String user, + @Nullable String group) + throws MinioException { + if (!(user != null ^ group != null)) { + throw new IllegalArgumentException("either user or group must be provided"); + } + + Map map = new HashMap<>(); + map.put("policies", polices); + if (user != null) { + map.put("user", user); + } else { + map.put("group", group); + } + + Credentials creds = getCredentials(); + try (Response response = + execute( + Http.Method.POST, + command, + null, + Crypto.encrypt(OBJECT_MAPPER.writeValueAsBytes(map), creds.secretKey()))) { + return OBJECT_MAPPER.readValue( + Crypto.decrypt(response.body().byteStream(), creds.secretKey()), + PolicyAssociationResponse.class); + } catch (JsonProcessingException e) { + throw new MinioException(e); + } catch (IOException e) { + throw new MinioException(e); } } + /** Attach policies to a user or group. */ + public PolicyAssociationResponse attachPolicy( + @Nonnull String[] policies, @Nullable String user, @Nullable String group) + throws MinioException { + return attachDetachPolicy(Command.IDP_BUILTIN_POLICY_ATTACH, policies, user, group); + } + + /** Detach policies from a user or group. */ + public PolicyAssociationResponse detachPolicy( + @Nonnull String[] policies, @Nullable String user, @Nullable String group) + throws MinioException { + return attachDetachPolicy(Command.IDP_BUILTIN_POLICY_DETACH, policies, user, group); + } + /** * Sets HTTP connect, write and read timeouts. A value of 0 means no timeout, otherwise values * must be between 1 and Integer.MAX_VALUE when converted to milliseconds. @@ -857,8 +878,7 @@ public GetServiceAccountInfoResp getServiceAccountInfo(@Nonnull String accessKey * @param readTimeout HTTP read timeout in milliseconds. */ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) { - this.httpClient = - HttpUtils.setTimeout(this.httpClient, connectTimeout, writeTimeout, readTimeout); + this.httpClient = Http.setTimeout(this.httpClient, connectTimeout, writeTimeout, readTimeout); } /** @@ -868,12 +888,11 @@ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) * client.ignoreCertCheck(); * } * - * @throws KeyManagementException thrown to indicate key management error. - * @throws NoSuchAlgorithmException thrown to indicate missing of SSL library. + * @throws MinioException thrown to indicate SDK exception. */ @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.") - public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmException { - this.httpClient = HttpUtils.disableCertCheck(this.httpClient); + public void ignoreCertCheck() throws MinioException { + this.httpClient = Http.disableCertCheck(this.httpClient); } /** @@ -885,8 +904,7 @@ public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmExce */ public void setAppInfo(String name, String version) { if (name == null || version == null) return; - this.userAgent = - MinioProperties.INSTANCE.getDefaultUserAgent() + " " + name.trim() + "/" + version.trim(); + this.userAgent = Utils.getDefaultUserAgent() + " " + name.trim() + "/" + version.trim(); } /** @@ -905,9 +923,8 @@ public void traceOn(OutputStream traceStream) { * Disables HTTP call tracing previously enabled. * * @see #traceOn - * @throws IOException upon connection error */ - public void traceOff() throws IOException { + public void traceOff() { this.traceStream = null; } @@ -923,12 +940,12 @@ public static final class Builder { private OkHttpClient httpClient; public Builder endpoint(String endpoint) { - this.baseUrl = HttpUtils.getBaseUrl(endpoint); + this.baseUrl = Utils.getBaseUrl(endpoint); return this; } public Builder endpoint(String endpoint, int port, boolean secure) { - HttpUrl url = HttpUtils.getBaseUrl(endpoint); + HttpUrl url = Utils.getBaseUrl(endpoint); if (port < 1 || port > 65535) { throw new IllegalArgumentException("port must be in range of 1 to 65535"); } @@ -938,20 +955,20 @@ public Builder endpoint(String endpoint, int port, boolean secure) { } public Builder endpoint(HttpUrl url) { - HttpUtils.validateNotNull(url, "url"); - HttpUtils.validateUrl(url); + Utils.validateNotNull(url, "url"); + Utils.validateUrl(url); this.baseUrl = url; return this; } public Builder endpoint(URL url) { - HttpUtils.validateNotNull(url, "url"); + Utils.validateNotNull(url, "url"); return endpoint(HttpUrl.get(url)); } public Builder region(String region) { - HttpUtils.validateNotNull(region, "region"); + Utils.validateNotNull(region, "region"); this.region = region; return this; } @@ -962,25 +979,21 @@ public Builder credentials(String accessKey, String secretKey) { } public Builder credentialsProvider(Provider provider) { - HttpUtils.validateNotNull(provider, "credential provider"); + Utils.validateNotNull(provider, "credential provider"); this.provider = provider; return this; } public Builder httpClient(OkHttpClient httpClient) { - HttpUtils.validateNotNull(httpClient, "http client"); + Utils.validateNotNull(httpClient, "http client"); this.httpClient = httpClient; return this; } public MinioAdminClient build() { - HttpUtils.validateNotNull(baseUrl, "base url"); - HttpUtils.validateNotNull(provider, "credential provider"); - if (httpClient == null) { - httpClient = - HttpUtils.newDefaultHttpClient( - DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); - } + Utils.validateNotNull(baseUrl, "base url"); + Utils.validateNotNull(provider, "credential provider"); + if (httpClient == null) httpClient = Http.newDefaultClient(); return new MinioAdminClient(baseUrl, region, provider, httpClient); } } diff --git a/adminapi/src/main/java/io/minio/admin/messages/TierStats.java b/adminapi/src/main/java/io/minio/admin/PolicyAssociationResponse.java similarity index 59% rename from adminapi/src/main/java/io/minio/admin/messages/TierStats.java rename to adminapi/src/main/java/io/minio/admin/PolicyAssociationResponse.java index 034fa40ca..54f8a32b1 100644 --- a/adminapi/src/main/java/io/minio/admin/messages/TierStats.java +++ b/adminapi/src/main/java/io/minio/admin/PolicyAssociationResponse.java @@ -15,37 +15,33 @@ * limitations under the License. */ -package io.minio.admin.messages; +package io.minio.admin; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.LocalDateTime; -/** - * Per-tier stats of a remote tier. - * - * @see data-usage-cache.go - */ +/** attachPolicy and detachPolicy response. */ @JsonIgnoreProperties(ignoreUnknown = true) -public class TierStats { - @JsonProperty("TotalSize") - private long totalSize; +public class PolicyAssociationResponse { + @JsonProperty("policiesAttached") + private String[] policiesAttached; - @JsonProperty("NumVersions") - private int numVersions; + @JsonProperty("policiesDetached") + private String[] policiesDetached; - @JsonProperty("NumObjects") - private int numObjects; + @JsonProperty("updatedAt") + private LocalDateTime updatedAt; - public long totalSize() { - return totalSize; + public String[] getPoliciesAttached() { + return policiesAttached; } - public int numVersions() { - return numVersions; + public String[] getPoliciesDetached() { + return policiesDetached; } - public int numObjects() { - return numObjects; + public LocalDateTime getUpdatedAt() { + return updatedAt; } } diff --git a/adminapi/src/main/java/io/minio/admin/UserInfo.java b/adminapi/src/main/java/io/minio/admin/UserInfo.java index fdc10fa13..6f0631dab 100644 --- a/adminapi/src/main/java/io/minio/admin/UserInfo.java +++ b/adminapi/src/main/java/io/minio/admin/UserInfo.java @@ -17,10 +17,8 @@ package io.minio.admin; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonValue; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -67,37 +65,4 @@ public List memberOf() { public Status status() { return status; } - - public static enum Status { - ENABLED("enabled"), - DISABLED("disabled"); - - private final String value; - - private Status(String value) { - this.value = value; - } - - @JsonValue - public String toString() { - return this.value; - } - - @JsonCreator - public static Status fromString(String statusString) { - if ("enabled".equals(statusString)) { - return ENABLED; - } - - if ("disabled".equals(statusString)) { - return DISABLED; - } - - if (statusString.isEmpty()) { - return null; - } - - throw new IllegalArgumentException("Unknown status " + statusString); - } - } } diff --git a/adminapi/src/main/java/io/minio/admin/messages/AllTierStats.java b/adminapi/src/main/java/io/minio/admin/messages/AllTierStats.java deleted file mode 100644 index 801178186..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/AllTierStats.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.Map; - -/** - * Collection of per-tier stats across all configured remote tiers - * - * @see data-usage-cache.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class AllTierStats { - @JsonProperty("Tiers") - private Map tiers; - - public Map tiers() { - return Collections.unmodifiableMap(this.tiers); - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/BucketTargetUsageInfo.java b/adminapi/src/main/java/io/minio/admin/messages/BucketTargetUsageInfo.java deleted file mode 100644 index 40dee2728..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/BucketTargetUsageInfo.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Represents bucket replica stats of the current object APi. - * - * @see data-usage-utils.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class BucketTargetUsageInfo { - @JsonProperty("objectsPendingReplicationTotalSize") - private long objectsPendingReplicationTotalSize; - - @JsonProperty("objectsFailedReplicationTotalSize") - private long objectsFailedReplicationTotalSize; - - @JsonProperty("objectsReplicatedTotalSize") - private long objectsReplicatedTotalSize; - - @JsonProperty("objectReplicaTotalSize") - private long objectReplicaTotalSize; - - @JsonProperty("objectsPendingReplicationCount") - private long objectsPendingReplicationCount; - - @JsonProperty("objectsFailedReplicationCount") - private long objectsFailedReplicationCount; - - public long objectsPendingReplicationTotalSize() { - return objectsPendingReplicationTotalSize; - } - - public long objectsFailedReplicationTotalSize() { - return objectsFailedReplicationTotalSize; - } - - public long objectsReplicatedTotalSize() { - return objectsReplicatedTotalSize; - } - - public long objectReplicaTotalSize() { - return objectReplicaTotalSize; - } - - public long objectsPendingReplicationCount() { - return objectsPendingReplicationCount; - } - - public long objectsFailedReplicationCount() { - return objectsFailedReplicationCount; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/BucketUsageInfo.java b/adminapi/src/main/java/io/minio/admin/messages/BucketUsageInfo.java deleted file mode 100644 index 91b47ced1..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/BucketUsageInfo.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.Map; - -/** - * Represents bucket usage stats of the current object APi. - * - * @see data-usage-utils.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class BucketUsageInfo { - @JsonProperty("size") - private long size; - - @JsonProperty("objectsPendingReplicationTotalSize") - private long objectsPendingReplicationTotalSize; - - @JsonProperty("objectsFailedReplicationTotalSize") - private long objectsFailedReplicationTotalSize; - - @JsonProperty("objectsReplicatedTotalSize") - private long objectsReplicatedTotalSize; - - @JsonProperty("objectsPendingReplicationCount") - private long objectsPendingReplicationCount; - - @JsonProperty("objectsFailedReplicationCount") - private long objectsFailedReplicationCount; - - @JsonProperty("objectsCount") - private long objectsCount; - - @JsonProperty("objectsSizesHistogram") - private Map objectsSizesHistogram; - - @JsonProperty("versionsCount") - private long versionsCount; - - @JsonProperty("objectReplicaTotalSize") - private long objectReplicaTotalSize; - - @JsonProperty("objectsReplicationInfo") - private Map objectsReplicationInfo; - - public long size() { - return size; - } - - public long objectsPendingReplicationTotalSize() { - return objectsPendingReplicationTotalSize; - } - - public long objectsFailedReplicationTotalSize() { - return objectsFailedReplicationTotalSize; - } - - public long objectsReplicatedTotalSize() { - return objectsReplicatedTotalSize; - } - - public long objectsPendingReplicationCount() { - return objectsPendingReplicationCount; - } - - public long objectsFailedReplicationCount() { - return objectsFailedReplicationCount; - } - - public long objectsCount() { - return objectsCount; - } - - public Map objectsSizesHistogram() { - return Collections.unmodifiableMap(this.objectsSizesHistogram); - } - - public long versionsCount() { - return versionsCount; - } - - public long objectReplicaTotalSize() { - return objectReplicaTotalSize; - } - - public Map objectsReplicationInfo() { - return Collections.unmodifiableMap(this.objectsReplicationInfo); - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/DataUsageInfo.java b/adminapi/src/main/java/io/minio/admin/messages/DataUsageInfo.java deleted file mode 100644 index 285aa9a04..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/DataUsageInfo.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.Map; - -/** - * Represents data usage stats of the current object APi. - * - * @see data-usage-utils.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class DataUsageInfo { - - @JsonProperty("lastUpdate") - private ZonedDateTime lastUpdate; - - @JsonProperty("objectsCount") - private long objectsCount; - - @JsonProperty("versionsCount") - private long versionsCount; - - @JsonProperty("objectsTotalSize") - private long objectsTotalSize; - - @JsonProperty("objectsReplicationInfo") - private Map objectsReplicationInfo; - - @JsonProperty("bucketsCount") - private long bucketsCount; - - @JsonProperty("bucketsUsageInfo") - private Map bucketsUsageInfo; - - @JsonProperty("bucketsSizes") - private Map bucketsSizes; - - @JsonProperty("tierStats") - private AllTierStats tierStats; - - public ZonedDateTime lastUpdate() { - return lastUpdate; - } - - public long objectsCount() { - return objectsCount; - } - - public long versionsCount() { - return versionsCount; - } - - public long objectsTotalSize() { - return objectsTotalSize; - } - - public Map objectsReplicationInfo() { - return Collections.unmodifiableMap(this.objectsReplicationInfo); - } - - public long bucketsCount() { - return bucketsCount; - } - - public Map bucketsUsageInfo() { - return Collections.unmodifiableMap(this.bucketsUsageInfo); - } - - public Map bucketsSizes() { - return Collections.unmodifiableMap(bucketsSizes); - } - - public AllTierStats tierStats() { - return tierStats; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Backend.java b/adminapi/src/main/java/io/minio/admin/messages/info/Backend.java deleted file mode 100644 index ae9f08319..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Backend.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * ErasureBackend contains specific erasure storage information - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Backend { - @JsonProperty("backendType") - private String backendType; - - @JsonProperty("onlineDisks") - private Integer onlineDisks; - - @JsonProperty("offlineDisks") - private Integer offlineDisks; - - @JsonProperty("standardSCParity") - private Integer standardSCParity; - - @JsonProperty("rrSCParity") - private Integer rrSCParity; - - @JsonProperty("totalSets") - private List totalSets; - - @JsonProperty("totalDrivesPerSet") - private List totalDrivesPerSet; - - public String backendType() { - return backendType; - } - - public Integer onlineDisks() { - return onlineDisks; - } - - public Integer offlineDisks() { - return offlineDisks; - } - - public Integer standardSCParity() { - return standardSCParity; - } - - public Integer rrSCParity() { - return rrSCParity; - } - - public List totalSets() { - return Collections.unmodifiableList(totalSets == null ? new LinkedList<>() : totalSets); - } - - public List totalDrivesPerSet() { - return Collections.unmodifiableList( - totalDrivesPerSet == null ? new LinkedList<>() : totalDrivesPerSet); - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Buckets.java b/adminapi/src/main/java/io/minio/admin/messages/info/Buckets.java deleted file mode 100644 index 54b16037c..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Buckets.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Buckets contains the number of buckets - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Buckets { - @JsonProperty("count") - private Integer count; - - @JsonProperty("error") - private String error; - - public Integer count() { - return count; - } - - public String error() { - return error; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Disk.java b/adminapi/src/main/java/io/minio/admin/messages/info/Disk.java deleted file mode 100644 index d6f2c39ed..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Disk.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; - -/** - * Disk holds Disk information - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Disk { - @JsonProperty("endpoint") - private String endpoint; - - @JsonProperty("rootDisk") - private boolean rootDisk; - - @JsonProperty("path") - private String path; - - @JsonProperty("healing") - private boolean healing; - - @JsonProperty("scanning") - private boolean scanning; - - @JsonProperty("state") - private String state; - - @JsonProperty("uuid") - private String uuid; - - @JsonProperty("major") - private BigDecimal major; - - @JsonProperty("minor") - private BigDecimal minor; - - @JsonProperty("model") - private String model; - - @JsonProperty("totalspace") - private BigDecimal totalspace; - - @JsonProperty("usedspace") - private BigDecimal usedspace; - - @JsonProperty("availspace") - private BigDecimal availspace; - - @JsonProperty("readthroughput") - private BigDecimal readthroughput; - - @JsonProperty("writethroughput") - private BigDecimal writethroughput; - - @JsonProperty("readlatency") - private BigDecimal readlatency; - - @JsonProperty("writelatency") - private BigDecimal writelatency; - - @JsonProperty("utilization") - private BigDecimal utilization; - - @JsonProperty("metrics") - private DiskMetrics metrics; - - @JsonProperty("heal_info") - private HealingDisk healInfo; - - @JsonProperty("used_inodes") - private BigDecimal usedInodes; - - @JsonProperty("free_inodes") - private BigDecimal freeInodes; - - @JsonProperty("pool_index") - private Integer poolIndex; - - @JsonProperty("set_index") - private Integer setIndex; - - @JsonProperty("disk_index") - private Integer diskIndex; - - public String endpoint() { - return endpoint; - } - - public boolean isRootDisk() { - return rootDisk; - } - - public String path() { - return path; - } - - public boolean isHealing() { - return healing; - } - - public boolean isScanning() { - return scanning; - } - - public String state() { - return state; - } - - public String uuid() { - return uuid; - } - - public BigDecimal major() { - return major; - } - - public BigDecimal minor() { - return minor; - } - - public String model() { - return model; - } - - public BigDecimal totalspace() { - return totalspace; - } - - public BigDecimal usedspace() { - return usedspace; - } - - public BigDecimal availspace() { - return availspace; - } - - public BigDecimal readthroughput() { - return readthroughput; - } - - public BigDecimal writethroughput() { - return writethroughput; - } - - public BigDecimal readlatency() { - return readlatency; - } - - public BigDecimal writelatency() { - return writelatency; - } - - public BigDecimal utilization() { - return utilization; - } - - public DiskMetrics metrics() { - return metrics; - } - - public HealingDisk healInfo() { - return healInfo; - } - - public BigDecimal usedInodes() { - return usedInodes; - } - - public BigDecimal freeInodes() { - return freeInodes; - } - - public Integer poolIndex() { - return poolIndex; - } - - public Integer setIndex() { - return setIndex; - } - - public Integer diskIndex() { - return diskIndex; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/DiskMetrics.java b/adminapi/src/main/java/io/minio/admin/messages/info/DiskMetrics.java deleted file mode 100644 index 1b1b35078..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/DiskMetrics.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.Map; - -/** - * DiskMetrics has the information about XL Storage APIs - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class DiskMetrics { - @JsonProperty("lastMinute") - private Map lastMinute; - - @JsonProperty("apiCalls") - private Map apiCalls; - - @JsonProperty("totalErrorsAvailability") - private Integer totalErrorsAvailability; - - @JsonProperty("totalErrorsTimeout") - private Integer totalErrorsTimeout; - - @JsonProperty("totalTokens") - private Long totalTokens; - - @JsonProperty("totalWaiting") - private Long totalWaiting; - - @JsonProperty("totalWrites") - private Long totalWrites; - - @JsonProperty("totalDeletes") - private Long totalDeletes; - - public Integer totalErrorsAvailability() { - return totalErrorsAvailability; - } - - public Integer totalErrorsTimeout() { - return totalErrorsTimeout; - } - - public Map lastMinute() { - return Collections.unmodifiableMap(lastMinute); - } - - public Map apiCalls() { - return Collections.unmodifiableMap(apiCalls); - } - - public Long totalTokens() { - return totalTokens; - } - - public Long totalWaiting() { - return totalWaiting; - } - - public Long totalWrites() { - return totalWrites; - } - - public Long totalDeletes() { - return totalDeletes; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/ErasureSetInfo.java b/adminapi/src/main/java/io/minio/admin/messages/info/ErasureSetInfo.java deleted file mode 100644 index 5b8102eec..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/ErasureSetInfo.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; - -/** - * ErasureSetInfo provides information per erasure set - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class ErasureSetInfo { - @JsonProperty("id") - private Integer id; - - @JsonProperty("rawUsage") - private BigDecimal rawUsage; - - @JsonProperty("rawCapacity") - private BigDecimal rawCapacity; - - @JsonProperty("usage") - private BigDecimal usage; - - @JsonProperty("objectsCount") - private BigDecimal objectsCount; - - @JsonProperty("versionsCount") - private BigDecimal versionsCount; - - @JsonProperty("healDisks") - private Integer healDisks; - - public Integer id() { - return id; - } - - public BigDecimal rawUsage() { - return rawUsage; - } - - public BigDecimal rawCapacity() { - return rawCapacity; - } - - public BigDecimal usage() { - return usage; - } - - public BigDecimal objectsCount() { - return objectsCount; - } - - public BigDecimal versionsCount() { - return versionsCount; - } - - public Integer healDisks() { - return healDisks; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/GCStats.java b/adminapi/src/main/java/io/minio/admin/messages/info/GCStats.java deleted file mode 100644 index 9a8b52d13..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/GCStats.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * GCStats collect information about recent garbage collections. - * - * @see health.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class GCStats { - @JsonProperty("last_gc") - private String lastGC; - - @JsonProperty("num_gc") - private Integer numGC; - - @JsonProperty("pause_total") - private Long pauseTotal; - - @JsonProperty("pause") - private List pause; - - @JsonProperty("pause_end") - private List pauseEnd; - - public String lastGC() { - return lastGC; - } - - public Integer numGC() { - return numGC; - } - - public Long pauseTotal() { - return pauseTotal; - } - - public List pause() { - return Collections.unmodifiableList(pause == null ? new LinkedList<>() : pause); - } - - public List pauseEnd() { - return Collections.unmodifiableList(pauseEnd == null ? new LinkedList<>() : pauseEnd); - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/HealingDisk.java b/adminapi/src/main/java/io/minio/admin/messages/info/HealingDisk.java deleted file mode 100644 index e87eb42a7..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/HealingDisk.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * HealingDisk contains information about - * - * @see heal-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class HealingDisk { - @JsonProperty("id") - private String id; - - @JsonProperty("heal_id") - private String healID; - - @JsonProperty("pool_index") - private Integer poolIndex; - - @JsonProperty("set_index") - private Integer setIndex; - - @JsonProperty("disk_index") - private Integer diskIndex; - - @JsonProperty("endpoint") - private String endpoint; - - @JsonProperty("path") - private String path; - - @JsonProperty("started") - private String started; - - @JsonProperty("last_update") - private String lastUpdate; - - @JsonProperty("objects_total_count") - private BigDecimal objectsTotalCount; - - @JsonProperty("objects_total_size") - private BigDecimal objectsTotalSize; - - @JsonProperty("items_healed") - private BigDecimal itemsHealed; - - @JsonProperty("items_failed") - private BigDecimal itemsFailed; - - @JsonProperty("bytes_done") - private BigDecimal bytesDone; - - @JsonProperty("bytes_failed") - private BigDecimal bytesFailed; - - @JsonProperty("objects_healed") - private BigDecimal objectsHealed; - - @JsonProperty("objects_failed") - private BigDecimal objectsFailed; - - @JsonProperty("current_bucket") - private String bucket; - - @JsonProperty("current_object") - private String object; - - @JsonProperty("queued_buckets") - private List queuedBuckets; - - @JsonProperty("healed_buckets") - private List healedBuckets; - - public String id() { - return id; - } - - public String healID() { - return healID; - } - - public Integer poolIndex() { - return poolIndex; - } - - public Integer setIndex() { - return setIndex; - } - - public Integer diskIndex() { - return diskIndex; - } - - public String endpoint() { - return endpoint; - } - - public String path() { - return path; - } - - public String started() { - return started; - } - - public String lastUpdate() { - return lastUpdate; - } - - public BigDecimal objectsTotalCount() { - return objectsTotalCount; - } - - public BigDecimal objectsTotalSize() { - return objectsTotalSize; - } - - public BigDecimal itemsHealed() { - return itemsHealed; - } - - public BigDecimal itemsFailed() { - return itemsFailed; - } - - public BigDecimal bytesDone() { - return bytesDone; - } - - public BigDecimal bytesFailed() { - return bytesFailed; - } - - public BigDecimal objectsHealed() { - return objectsHealed; - } - - public BigDecimal objectsFailed() { - return objectsFailed; - } - - public String bucket() { - return bucket; - } - - public String object() { - return object; - } - - public List queuedBuckets() { - return Collections.unmodifiableList(queuedBuckets == null ? new LinkedList<>() : queuedBuckets); - } - - public List healedBuckets() { - return Collections.unmodifiableList(healedBuckets == null ? new LinkedList<>() : healedBuckets); - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/MemStats.java b/adminapi/src/main/java/io/minio/admin/messages/info/MemStats.java deleted file mode 100644 index 1f692e9d1..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/MemStats.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; - -/** - * MemStats is strip down version of runtime.MemStats containing memory stats of MinIO server. - * - * @see health.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class MemStats { - @JsonProperty("Alloc") - private BigDecimal alloc; - - @JsonProperty("TotalAlloc") - private BigDecimal totalAlloc; - - @JsonProperty("Mallocs") - private BigDecimal mallocs; - - @JsonProperty("Frees") - private BigDecimal frees; - - @JsonProperty("HeapAlloc") - private BigDecimal heapAlloc; - - public BigDecimal alloc() { - return alloc; - } - - public BigDecimal totalAlloc() { - return totalAlloc; - } - - public BigDecimal mallocs() { - return mallocs; - } - - public BigDecimal frees() { - return frees; - } - - public BigDecimal heapAlloc() { - return heapAlloc; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Message.java b/adminapi/src/main/java/io/minio/admin/messages/info/Message.java deleted file mode 100644 index 1515ddfc6..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Message.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * InfoMessage container to hold server admin related information. - * - * @see heal-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Message { - @JsonProperty("mode") - private String mode; - - @JsonProperty("deploymentID") - private String deploymentID; - - @JsonProperty("buckets") - private Buckets buckets; - - @JsonProperty("objects") - private Objects objects; - - @JsonProperty("versions") - private Versions versions; - - @JsonProperty("usage") - private Usage usage; - - @JsonProperty("backend") - private Backend backend; - - @JsonProperty("servers") - private List servers; - - @JsonProperty("pools") - private Map> pools; - - public String mode() { - return mode; - } - - public String deploymentID() { - return deploymentID; - } - - public Buckets buckets() { - return buckets; - } - - public Objects objects() { - return objects; - } - - public Versions versions() { - return versions; - } - - public Usage usage() { - return usage; - } - - public Backend backend() { - return backend; - } - - public List servers() { - return Collections.unmodifiableList(servers == null ? new LinkedList<>() : servers); - } - - public Map> pools() { - return pools; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Objects.java b/adminapi/src/main/java/io/minio/admin/messages/info/Objects.java deleted file mode 100644 index 0e072260b..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Objects.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Objects contains the number of objects - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Objects { - @JsonProperty("count") - private Integer count; - - @JsonProperty("error") - private String error; - - public Integer count() { - return count; - } - - public String error() { - return error; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/ServerProperties.java b/adminapi/src/main/java/io/minio/admin/messages/info/ServerProperties.java deleted file mode 100644 index 0b33dc282..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/ServerProperties.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * ServerProperties holds server information - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class ServerProperties { - @JsonProperty("state") - private String state; - - @JsonProperty("endpoint") - private String endpoint; - - @JsonProperty("scheme") - private String scheme; - - @JsonProperty("uptime") - private Integer uptime; - - @JsonProperty("version") - private String version; - - @JsonProperty("commitID") - private String commitID; - - @JsonProperty("network") - private Map network; - - @JsonProperty("drives") - private List disks; - - @JsonProperty("poolNumber") - private Integer poolNumber; - - @JsonProperty("mem_stats") - private MemStats memStats; - - @JsonProperty("go_max_procs") - private Integer goMaxProcs; - - @JsonProperty("num_cpu") - private Integer numCPU; - - @JsonProperty("runtime_version") - private String runtimeVersion; - - @JsonProperty("gc_stats") - private GCStats gCStats; - - @JsonProperty("minio_env_vars") - private Map minioEnvVars; - - public String state() { - return state; - } - - public String endpoint() { - return endpoint; - } - - public String scheme() { - return scheme; - } - - public Integer uptime() { - return uptime; - } - - public String version() { - return version; - } - - public String commitID() { - return commitID; - } - - public Map network() { - return Collections.unmodifiableMap(this.network); - } - - public List disks() { - return Collections.unmodifiableList(disks == null ? new LinkedList<>() : disks); - } - - public Integer poolNumber() { - return poolNumber; - } - - public MemStats memStats() { - return memStats; - } - - public Integer goMaxProcs() { - return goMaxProcs; - } - - public Integer numCPU() { - return numCPU; - } - - public String runtimeVersion() { - return runtimeVersion; - } - - public GCStats gCStats() { - return gCStats; - } - - public Map minioEnvVars() { - return Collections.unmodifiableMap(this.minioEnvVars); - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/TimedAction.java b/adminapi/src/main/java/io/minio/admin/messages/info/TimedAction.java deleted file mode 100644 index f1cde4185..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/TimedAction.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.math.BigDecimal; - -/** - * TimedAction contains a number of actions and their accumulated duration in nanoseconds. - * - * @see metrics.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class TimedAction { - @JsonProperty("count") - private BigDecimal count; - - @JsonProperty("acc_time_ns") - private BigDecimal accTime; - - @JsonProperty("bytes") - private BigDecimal bytes; - - public BigDecimal count() { - return count; - } - - public BigDecimal accTime() { - return accTime; - } - - public BigDecimal bytes() { - return bytes; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Usage.java b/adminapi/src/main/java/io/minio/admin/messages/info/Usage.java deleted file mode 100644 index 9c43d85e8..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Usage.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Usage contains the total size used - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Usage { - @JsonProperty("size") - private Long size; - - @JsonProperty("error") - private String error; - - public Long size() { - return size; - } - - public String error() { - return error; - } -} diff --git a/adminapi/src/main/java/io/minio/admin/messages/info/Versions.java b/adminapi/src/main/java/io/minio/admin/messages/info/Versions.java deleted file mode 100644 index 67efc6fc2..000000000 --- a/adminapi/src/main/java/io/minio/admin/messages/info/Versions.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages.info; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Versions contains the number of versions - * - * @see info-commands.go - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Versions { - @JsonProperty("count") - private Integer count; - - @JsonProperty("error") - private String error; - - public Integer count() { - return count; - } - - public String error() { - return error; - } -} diff --git a/adminapi/src/test/java/io/minio/admin/messages/DataUsageInfoTest.java b/adminapi/src/test/java/io/minio/admin/messages/DataUsageInfoTest.java deleted file mode 100644 index dfe01b7a0..000000000 --- a/adminapi/src/test/java/io/minio/admin/messages/DataUsageInfoTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2022 MinIO, 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 io.minio.admin.messages; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import java.io.File; -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import org.junit.Assert; -import org.junit.Test; - -public class DataUsageInfoTest { - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - static { - OBJECT_MAPPER.registerModule(new JavaTimeModule()); - } - - @Test - public void deserializeTest() throws IOException { - - DataUsageInfo info = - OBJECT_MAPPER.readValue( - new File( - getClass().getClassLoader().getResource("messages/datausageinfo.json").getFile()), - DataUsageInfo.class); - Assert.assertNotNull(info.lastUpdate()); - Assert.assertEquals( - 15, LocalDateTime.ofInstant(info.lastUpdate().toInstant(), ZoneOffset.UTC).getHour()); - - Assert.assertEquals(1, info.bucketsCount()); - Assert.assertTrue(info.bucketsUsageInfo().containsKey("tier-bucket")); - Assert.assertTrue(info.tierStats().tiers().containsKey("STANDARD")); - - Assert.assertEquals(7155L, (long) info.bucketsSizes().get("tier-bucket")); - } -} diff --git a/api/src/main/java/io/minio/AbortMultipartUploadArgs.java b/api/src/main/java/io/minio/AbortMultipartUploadArgs.java new file mode 100644 index 000000000..e18755c63 --- /dev/null +++ b/api/src/main/java/io/minio/AbortMultipartUploadArgs.java @@ -0,0 +1,73 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#abortMultipartUpload}. */ +public class AbortMultipartUploadArgs extends ObjectArgs { + private String uploadId; + + protected AbortMultipartUploadArgs() {} + + public AbortMultipartUploadArgs(ComposeObjectArgs args, String uploadId) { + super(args); + this.uploadId = uploadId; + } + + public AbortMultipartUploadArgs(PutObjectBaseArgs args, String uploadId) { + super(args); + this.uploadId = uploadId; + } + + public String uploadId() { + return uploadId; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link AbortMultipartUploadArgs}. */ + public static final class Builder extends ObjectArgs.Builder { + @Override + protected void validate(AbortMultipartUploadArgs args) { + super.validate(args); + Utils.validateNotEmptyString(args.uploadId, "upload ID"); + } + + public Builder uploadId(String uploadId) { + Utils.validateNotEmptyString(uploadId, "upload ID"); + operations.add(args -> args.uploadId = uploadId); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AbortMultipartUploadArgs)) return false; + if (!super.equals(o)) return false; + AbortMultipartUploadArgs that = (AbortMultipartUploadArgs) o; + return Objects.equals(uploadId, that.uploadId); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), uploadId); + } +} diff --git a/api/src/main/java/io/minio/AbortMultipartUploadResponse.java b/api/src/main/java/io/minio/AbortMultipartUploadResponse.java index ee36bb4c5..f08166391 100644 --- a/api/src/main/java/io/minio/AbortMultipartUploadResponse.java +++ b/api/src/main/java/io/minio/AbortMultipartUploadResponse.java @@ -18,7 +18,7 @@ import okhttp3.Headers; -/** Response class of {@link S3Base#abortMultipartUploadAsync}. */ +/** Response of {@link BaseS3Client#abortMultipartUpload}. */ public class AbortMultipartUploadResponse extends GenericResponse { private String uploadId; diff --git a/api/src/main/java/io/minio/BaseArgs.java b/api/src/main/java/io/minio/BaseArgs.java index c8857ec55..12b156ec2 100644 --- a/api/src/main/java/io/minio/BaseArgs.java +++ b/api/src/main/java/io/minio/BaseArgs.java @@ -16,9 +16,6 @@ package io.minio; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -26,29 +23,45 @@ import java.util.Map; import java.util.Objects; import java.util.function.Consumer; -import okhttp3.HttpUrl; -/** Base argument class. */ +/** + * Common arguments of {@link BucketArgs}, {@link ListBucketsArgs} and {@link PutObjectFanOutEntry}. + */ public abstract class BaseArgs { - protected Multimap extraHeaders = - Multimaps.unmodifiableMultimap(HashMultimap.create()); - protected Multimap extraQueryParams = - Multimaps.unmodifiableMultimap(HashMultimap.create()); + protected String location; + protected Http.Headers extraHeaders; + protected Http.QueryParameters extraQueryParams; + + protected BaseArgs() {} + + protected BaseArgs(BaseArgs args) { + this.location = args.location; + this.extraHeaders = args.extraHeaders; + this.extraQueryParams = args.extraQueryParams; + } + + public void setLocation(String location) { + this.location = location; + } + + public String location() { + return location; + } - public Multimap extraHeaders() { + public Http.Headers extraHeaders() { return extraHeaders; } - public Multimap extraQueryParams() { + public Http.QueryParameters extraQueryParams() { return extraQueryParams; } - protected void checkSse(ServerSideEncryption sse, HttpUrl url) { + protected void checkSse(ServerSideEncryption sse, boolean isHttps) { if (sse == null) { return; } - if (sse.tlsRequired() && !url.isHttps()) { + if (sse.tlsRequired() && !isHttps) { throw new IllegalArgumentException( sse + " operations must be performed over a secure connection."); } @@ -60,77 +73,32 @@ public abstract static class Builder, A extends BaseArgs protected abstract void validate(A args); - protected void validateNotNull(Object arg, String argName) { - if (arg == null) { - throw new IllegalArgumentException(argName + " must not be null."); - } - } - - protected void validateNotEmptyString(String arg, String argName) { - validateNotNull(arg, argName); - if (arg.isEmpty()) { - throw new IllegalArgumentException(argName + " must be a non-empty string."); - } - } - - protected void validateNullOrNotEmptyString(String arg, String argName) { - if (arg != null && arg.isEmpty()) { - throw new IllegalArgumentException(argName + " must be a non-empty string."); - } - } - - protected void validateNullOrPositive(Number arg, String argName) { - if (arg != null && arg.longValue() < 0) { - throw new IllegalArgumentException(argName + " cannot be non-negative."); - } - } - public Builder() { this.operations = new ArrayList<>(); } - protected Multimap copyMultimap(Multimap multimap) { - Multimap multimapCopy = HashMultimap.create(); - if (multimap != null) { - multimapCopy.putAll(multimap); - } - return Multimaps.unmodifiableMultimap(multimapCopy); - } - - protected Multimap toMultimap(Map map) { - Multimap multimap = HashMultimap.create(); - if (map != null) { - multimap.putAll(Multimaps.forMap(map)); - } - return Multimaps.unmodifiableMultimap(multimap); - } - @SuppressWarnings("unchecked") // Its safe to type cast to B as B extends this class. - public B extraHeaders(Multimap headers) { - final Multimap extraHeaders = copyMultimap(headers); + public B extraHeaders(Http.Headers headers) { + final Http.Headers extraHeaders = new Http.Headers(headers); operations.add(args -> args.extraHeaders = extraHeaders); return (B) this; } @SuppressWarnings("unchecked") // Its safe to type cast to B as B extends this class. - public B extraQueryParams(Multimap queryParams) { - final Multimap extraQueryParams = copyMultimap(queryParams); + public B extraQueryParams(Http.QueryParameters queryParams) { + final Http.QueryParameters extraQueryParams = new Http.QueryParameters(queryParams); operations.add(args -> args.extraQueryParams = extraQueryParams); return (B) this; } @SuppressWarnings("unchecked") // Its safe to type cast to B as B extends this class. public B extraHeaders(Map headers) { - final Multimap extraHeaders = toMultimap(headers); - operations.add(args -> args.extraHeaders = extraHeaders); - return (B) this; + return extraHeaders(new Http.Headers(headers)); } @SuppressWarnings("unchecked") // Its safe to type cast to B as B extends this class. public B extraQueryParams(Map queryParams) { - final Multimap extraQueryParams = toMultimap(queryParams); - operations.add(args -> args.extraQueryParams = extraQueryParams); - return (B) this; + return extraQueryParams(new Http.QueryParameters(queryParams)); } @SuppressWarnings("unchecked") // safe as B will always be the builder of the current args class diff --git a/api/src/main/java/io/minio/BaseClient.java.old b/api/src/main/java/io/minio/BaseClient.java.old new file mode 100644 index 000000000..7061d2e84 --- /dev/null +++ b/api/src/main/java/io/minio/BaseClient.java.old @@ -0,0 +1,173 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import io.minio.errors.InsufficientDataException; +import io.minio.errors.InternalException; +import io.minio.errors.XmlParserException; +import io.minio.messages.Part; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; + +/** Core S3 API client. */ +public abstract class BaseClient extends BaseS3Client { + ///////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// + + private Part[] uploadParts( + PutObjectBaseArgs args, String uploadId, PartReader partReader, PartSource firstPartSource) + throws InterruptedException, ExecutionException, InsufficientDataException, InternalException, + InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { + Part[] parts = new Part[ObjectWriteArgs.MAX_MULTIPART_COUNT]; + int partNumber = 0; + PartSource partSource = firstPartSource; + while (true) { + partNumber++; + + Multimap ssecHeaders = null; + // set encryption headers in the case of SSE-C. + if (args.sse() != null && args.sse() instanceof ServerSideEncryption.CustomerKey) { + ssecHeaders = Multimaps.forMap(args.sse().headers()); + } + + UploadPartResponse response = + uploadPart( + UploadPartArgs.builder() + .bucket(args.bucket()) + .region(args.region()) + .object(args.object()) + .buffer(partSource, partSource.size()) + .partNumber(partNumber) + .uploadId(uploadId) + .headers(ssecHeaders) + .build()) + .get(); + parts[partNumber - 1] = new Part(partNumber, response.etag()); + + partSource = partReader.getPart(); + if (partSource == null) break; + } + + return parts; + } + + private CompletableFuture putMultipartObjectAsync( + PutObjectBaseArgs args, + Multimap headers, + PartReader partReader, + PartSource firstPartSource) + throws InsufficientDataException, InternalException, InvalidKeyException, IOException, + NoSuchAlgorithmException, XmlParserException { + return CompletableFuture.supplyAsync( + () -> { + String uploadId = null; + ObjectWriteResponse response = null; + try { + CreateMultipartUploadResponse createMultipartUploadResponse = + createMultipartUpload( + CreateMultipartUploadArgs.builder() + .extraQueryParams(args.extraQueryParams()) + .bucket(args.bucket()) + .region(args.region()) + .object(args.object()) + .headers(headers) + .build()) + .get(); + uploadId = createMultipartUploadResponse.result().uploadId(); + Part[] parts = uploadParts(args, uploadId, partReader, firstPartSource); + response = + completeMultipartUpload( + CompleteMultipartUploadArgs.builder() + .bucket(args.bucket()) + .region(args.region()) + .object(args.object()) + .uploadId(uploadId) + .parts(parts) + .build()) + .get(); + } catch (InsufficientDataException + | InternalException + | InvalidKeyException + | IOException + | NoSuchAlgorithmException + | XmlParserException + | InterruptedException + | ExecutionException e) { + Throwable throwable = e; + if (throwable instanceof ExecutionException) { + throwable = ((ExecutionException) throwable).getCause(); + } + if (throwable instanceof CompletionException) { + throwable = ((CompletionException) throwable).getCause(); + } + if (uploadId == null) { + throw new CompletionException(throwable); + } + try { + abortMultipartUpload( + AbortMultipartUploadArgs.builder() + .bucket(args.bucket()) + .region(args.region()) + .object(args.object()) + .uploadId(uploadId) + .build()) + .get(); + } catch (InsufficientDataException + | InternalException + | InvalidKeyException + | IOException + | NoSuchAlgorithmException + | XmlParserException + | InterruptedException + | ExecutionException ex) { + throwable = ex; + if (throwable instanceof ExecutionException) { + throwable = ((ExecutionException) throwable).getCause(); + } + if (throwable instanceof CompletionException) { + throwable = ((CompletionException) throwable).getCause(); + } + } + throw new CompletionException(throwable); + } + return response; + }); + } + + protected PartReader newPartReader( + Object data, long objectSize, long partSize, int partCount, Checksum.Algorithm... algorithms) + throws NoSuchAlgorithmException { + if (data instanceof RandomAccessFile) { + return new PartReader((RandomAccessFile) data, objectSize, partSize, partCount, algorithms); + } + + if (data instanceof InputStream) { + return new PartReader((InputStream) data, objectSize, partSize, partCount, algorithms); + } + + return null; + } +} diff --git a/api/src/main/java/io/minio/BaseS3Client.java b/api/src/main/java/io/minio/BaseS3Client.java new file mode 100644 index 000000000..026299300 --- /dev/null +++ b/api/src/main/java/io/minio/BaseS3Client.java @@ -0,0 +1,1389 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2025 MinIO, 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 io.minio; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.google.common.collect.ImmutableSet; +import io.minio.credentials.Credentials; +import io.minio.credentials.Provider; +import io.minio.errors.ErrorResponseException; +import io.minio.errors.InternalException; +import io.minio.errors.InvalidResponseException; +import io.minio.errors.MinioException; +import io.minio.errors.ServerException; +import io.minio.errors.XmlParserException; +import io.minio.messages.CompleteMultipartUpload; +import io.minio.messages.CompleteMultipartUploadResult; +import io.minio.messages.CopyObjectResult; +import io.minio.messages.CopyPartResult; +import io.minio.messages.CreateBucketConfiguration; +import io.minio.messages.DeleteRequest; +import io.minio.messages.DeleteResult; +import io.minio.messages.ErrorResponse; +import io.minio.messages.InitiateMultipartUploadResult; +import io.minio.messages.ListAllMyBucketsResult; +import io.minio.messages.ListBucketResultV1; +import io.minio.messages.ListBucketResultV2; +import io.minio.messages.ListMultipartUploadsResult; +import io.minio.messages.ListPartsResult; +import io.minio.messages.ListVersionsResult; +import io.minio.messages.LocationConstraint; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; +import javax.annotation.Nonnull; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +/** Core S3 API client. */ +public abstract class BaseS3Client implements AutoCloseable { + static { + try { + RequestBody.create(new byte[] {}, null); + } catch (NoSuchMethodError ex) { + throw new RuntimeException("Unsupported OkHttp library found. Must use okhttp >= 4.11.0", ex); + } + } + + protected static final String NO_SUCH_BUCKET_MESSAGE = "Bucket does not exist"; + protected static final String NO_SUCH_BUCKET = "NoSuchBucket"; + protected static final String NO_SUCH_BUCKET_POLICY = "NoSuchBucketPolicy"; + protected static final String NO_SUCH_OBJECT_LOCK_CONFIGURATION = "NoSuchObjectLockConfiguration"; + protected static final String SERVER_SIDE_ENCRYPTION_CONFIGURATION_NOT_FOUND_ERROR = + "ServerSideEncryptionConfigurationNotFoundError"; + // maximum allowed bucket policy size is 20KiB + protected static final int MAX_BUCKET_POLICY_SIZE = 20 * 1024; + protected final Map regionCache = new ConcurrentHashMap<>(); + protected static final Random random = new Random(new SecureRandom().nextLong()); + protected static final ObjectMapper objectMapper = + JsonMapper.builder() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true) + .build(); + + private static final String RETRY_HEAD = "RetryHead"; + private static final String END_HTTP = "----------END-HTTP----------"; + private static final String UPLOAD_ID = "uploadId"; + private static final Set TRACE_QUERY_PARAMS = + ImmutableSet.of("retention", "legal-hold", "tagging", UPLOAD_ID, "acl", "attributes"); + private PrintWriter traceStream; + protected String userAgent = Utils.getDefaultUserAgent(); + + protected Http.BaseUrl baseUrl; + protected Provider provider; + protected OkHttpClient httpClient; + protected boolean closeHttpClient; + + protected BaseS3Client( + Http.BaseUrl baseUrl, Provider provider, OkHttpClient httpClient, boolean closeHttpClient) { + this.baseUrl = baseUrl; + this.provider = provider; + this.httpClient = httpClient; + this.closeHttpClient = closeHttpClient; + } + + protected BaseS3Client(BaseS3Client client) { + this.baseUrl = client.baseUrl; + this.provider = client.provider; + this.httpClient = client.httpClient; + this.closeHttpClient = client.closeHttpClient; + } + + @Override + public void close() throws Exception { + if (closeHttpClient) { + httpClient.dispatcher().executorService().shutdown(); + httpClient.connectionPool().evictAll(); + } + } + + /** + * Sets HTTP connect, write and read timeouts. A value of 0 means no timeout, otherwise values + * must be between 1 and Integer.MAX_VALUE when converted to milliseconds. + * + *
Example:{@code
+   * minioClient.setTimeout(TimeUnit.SECONDS.toMillis(10), TimeUnit.SECONDS.toMillis(10),
+   *     TimeUnit.SECONDS.toMillis(30));
+   * }
+ * + * @param connectTimeout HTTP connect timeout in milliseconds. + * @param writeTimeout HTTP write timeout in milliseconds. + * @param readTimeout HTTP read timeout in milliseconds. + */ + public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) { + this.httpClient = Http.setTimeout(this.httpClient, connectTimeout, writeTimeout, readTimeout); + } + + /** + * Ignores check on server certificate for HTTPS connection. + * + *
Example:{@code
+   * minioClient.ignoreCertCheck();
+   * }
+ * + * @throws MinioException thrown to indicate SDK exception. + */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SIC", + justification = "Should not be used in production anyways.") + public void ignoreCertCheck() throws MinioException { + this.httpClient = Http.disableCertCheck(this.httpClient); + } + + /** + * Sets application's name/version to user agent. For more information about user agent refer #rfc2616. + * + * @param name Your application name. + * @param version Your application version. + */ + public void setAppInfo(String name, String version) { + if (name == null || version == null) return; + this.userAgent = Utils.getDefaultUserAgent() + " " + name.trim() + "/" + version.trim(); + } + + /** + * Enables HTTP call tracing and written to traceStream. + * + * @param traceStream {@link OutputStream} for writing HTTP call tracing. + * @see #traceOff + */ + public void traceOn(OutputStream traceStream) { + if (traceStream == null) throw new IllegalArgumentException("trace stream must be provided"); + this.traceStream = + new PrintWriter(new OutputStreamWriter(traceStream, StandardCharsets.UTF_8), true); + } + + /** + * Disables HTTP call tracing previously enabled. + * + * @see #traceOn + */ + public void traceOff() { + this.traceStream = null; + } + + /** Enables dual-stack endpoint for Amazon S3 endpoint. */ + public void enableDualStackEndpoint() { + baseUrl.enableDualStackEndpoint(); + } + + /** Disables dual-stack endpoint for Amazon S3 endpoint. */ + public void disableDualStackEndpoint() { + baseUrl.disableDualStackEndpoint(); + } + + /** Enables virtual-style endpoint. */ + public void enableVirtualStyleEndpoint() { + baseUrl.enableVirtualStyleEndpoint(); + } + + /** Disables virtual-style endpoint. */ + public void disableVirtualStyleEndpoint() { + baseUrl.disableVirtualStyleEndpoint(); + } + + /** Sets AWS S3 domain prefix. */ + public void setAwsS3Prefix(@Nonnull String awsS3Prefix) { + baseUrl.setAwsS3Prefix(awsS3Prefix); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////// HTTP execution methods //////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// + + private String[] handleRedirectResponse( + Http.Method method, String bucketName, Response response, boolean retry) { + String code = null; + String message = null; + + if (response.code() == 301) { + code = "PermanentRedirect"; + message = "Moved Permanently"; + } else if (response.code() == 307) { + code = "Redirect"; + message = "Temporary redirect"; + } else if (response.code() == 400) { + code = "BadRequest"; + message = "Bad request"; + } + + String region = response.headers().get("x-amz-bucket-region"); + if (message != null && region != null) message += ". Use region " + region; + + if (retry + && region != null + && method.equals(Http.Method.HEAD) + && bucketName != null + && regionCache.get(bucketName) != null) { + code = RETRY_HEAD; + message = null; + } + + return new String[] {code, message}; + } + + /** Execute HTTP request asynchronously for given parameters. */ + protected CompletableFuture executeAsync(Http.S3Request s3request, String region) + throws MinioException { + Credentials credentials = (provider == null) ? null : provider.fetch(); + Http.Request request = s3request.toRequest(baseUrl, region, credentials); + + StringBuilder traceBuilder = new StringBuilder(request.httpTraces()); + PrintWriter traceStream = this.traceStream; + if (traceStream != null) traceStream.print(request.httpTraces()); + + OkHttpClient httpClient = this.httpClient; + // FIXME: enable retry for all request. + // if (!s3request.retryFailure()) { + // httpClient = httpClient.newBuilder().retryOnConnectionFailure(false).build(); + // } + + okhttp3.Request httpRequest = request.httpRequest(); + CompletableFuture completableFuture = new CompletableFuture<>(); + httpClient + .newCall(httpRequest) + .enqueue( + new Callback() { + @Override + public void onFailure(final Call call, IOException e) { + completableFuture.completeExceptionally(e); + } + + @Override + public void onResponse(Call call, final Response response) throws IOException { + try { + onResponse(response); + } catch (Exception e) { + completableFuture.completeExceptionally(e); + } + } + + private void onResponse(final Response response) throws IOException { + String trace = + String.format( + "%s %d %s%n%s", + response.protocol().toString().toUpperCase(Locale.US), + response.code(), + response.message(), + response.headers().toString()); + if (!trace.endsWith("\n\n")) { + trace += trace.endsWith("\n") ? "\n" : "\n\n"; + } + traceBuilder.append(trace); + if (traceStream != null) traceStream.print(trace); + + if (response.isSuccessful()) { + if (traceStream != null) { + // Trace response body only if the request is not + // GetObject/ListenBucketNotification + // S3 API. + Set keys = s3request.queryParams().keySet(); + if ((s3request.method() != Http.Method.GET + || s3request.object() == null + || !Collections.disjoint(keys, TRACE_QUERY_PARAMS)) + && !(keys.contains("events") + && (keys.contains("prefix") || keys.contains("suffix")))) { + String responseBody = response.peekBody(1024 * 1024).string(); + traceStream.print(responseBody); + if (!responseBody.endsWith("\n")) traceStream.println(); + } + traceStream.println(END_HTTP); + } + + completableFuture.complete(response); + return; + } + + String errorXml = null; + try (ResponseBody responseBody = response.body()) { + errorXml = responseBody.string(); + } + + if (!("".equals(errorXml) && s3request.method().equals(Http.Method.HEAD))) { + traceBuilder.append(errorXml); + if (traceStream != null) traceStream.print(errorXml); + if (!errorXml.endsWith("\n")) { + traceBuilder.append("\n"); + if (traceStream != null) traceStream.println(); + } + } + traceBuilder.append(END_HTTP).append("\n"); + if (traceStream != null) traceStream.println(END_HTTP); + + // Error out for Non-XML response from server for non-HEAD requests. + String contentType = response.headers().get(Http.Headers.CONTENT_TYPE); + if (!s3request.method().equals(Http.Method.HEAD) + && (contentType == null + || !Arrays.asList(contentType.split(";")).contains("application/xml"))) { + if (response.code() == 304 && response.body().contentLength() == 0) { + completableFuture.completeExceptionally( + new ServerException( + "server failed with HTTP status code " + response.code(), + response.code(), + traceBuilder.toString())); + } + + completableFuture.completeExceptionally( + new InvalidResponseException( + response.code(), + contentType, + errorXml.substring( + 0, errorXml.length() > 1024 ? 1024 : errorXml.length()), + traceBuilder.toString())); + return; + } + + ErrorResponse errorResponse = null; + if (!"".equals(errorXml)) { + try { + errorResponse = Xml.unmarshal(ErrorResponse.class, errorXml); + } catch (XmlParserException e) { + completableFuture.completeExceptionally(e); + return; + } + } else if (!s3request.method().equals(Http.Method.HEAD)) { + completableFuture.completeExceptionally( + new InvalidResponseException( + response.code(), contentType, errorXml, traceBuilder.toString())); + return; + } + + if (errorResponse == null) { + String code = null; + String message = null; + switch (response.code()) { + case 301: + case 307: + case 400: + String[] result = + handleRedirectResponse( + s3request.method(), s3request.bucket(), response, true); + code = result[0]; + message = result[1]; + break; + case 404: + if (s3request.object() != null) { + code = "NoSuchKey"; + message = "Object does not exist"; + } else if (s3request.bucket() != null) { + code = NO_SUCH_BUCKET; + message = NO_SUCH_BUCKET_MESSAGE; + } else { + code = "ResourceNotFound"; + message = "Request resource not found"; + } + break; + case 501: + case 405: + code = "MethodNotAllowed"; + message = "The specified method is not allowed against this resource"; + break; + case 409: + if (s3request.bucket() != null) { + code = NO_SUCH_BUCKET; + message = NO_SUCH_BUCKET_MESSAGE; + } else { + code = "ResourceConflict"; + message = "Request resource conflicts"; + } + break; + case 403: + code = "AccessDenied"; + message = "Access denied"; + break; + case 412: + code = "PreconditionFailed"; + message = "At least one of the preconditions you specified did not hold"; + break; + case 416: + code = "InvalidRange"; + message = "The requested range cannot be satisfied"; + break; + default: + completableFuture.completeExceptionally( + new ServerException( + "server failed with HTTP status code " + response.code(), + response.code(), + traceBuilder.toString())); + return; + } + + errorResponse = + new ErrorResponse( + code, + message, + s3request.bucket(), + s3request.object(), + httpRequest.url().encodedPath(), + response.header("x-amz-request-id"), + response.header("x-amz-id-2")); + } + + // invalidate region cache if needed + if (errorResponse.code().equals(NO_SUCH_BUCKET) + || errorResponse.code().equals(RETRY_HEAD)) { + regionCache.remove(s3request.bucket()); + } + + ErrorResponseException e = + new ErrorResponseException(errorResponse, response, traceBuilder.toString()); + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + /** Execute HTTP request asynchronously for given args and parameters. */ + protected CompletableFuture executeAsync(Http.S3Request s3request) + throws MinioException { + return getRegion(s3request.bucket(), s3request.region()) + .thenCompose( + location -> { + s3request.args().setLocation(location); + try { + return executeAsync(s3request, location); + } catch (MinioException e) { + throw new CompletionException(e); + } + }); + } + + /** Execute asynchronously GET HTTP request for given parameters. */ + protected CompletableFuture executeGetAsync( + BaseArgs args, Http.Headers headers, Http.QueryParameters queryParams) throws MinioException { + return executeAsync( + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.GET) + .headers(headers) + .queryParams(queryParams) + .args(args) + .build()); + } + + /** Execute asynchronously HEAD HTTP request for given parameters. */ + protected CompletableFuture executeHeadAsync( + BaseArgs args, Http.Headers headers, Http.QueryParameters queryParams) throws MinioException { + Http.S3Request s3request = + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.HEAD) + .headers(headers) + .queryParams(queryParams) + .args(args) + .build(); + return executeAsync(s3request) + .exceptionally( + e -> { + if (e instanceof ErrorResponseException) { + ErrorResponseException ex = (ErrorResponseException) e; + if (ex.errorResponse().code().equals(RETRY_HEAD)) { + return null; + } + } + throw new CompletionException(e); + }) + .thenCompose( + response -> { + if (response != null) { + return CompletableFuture.completedFuture(response); + } + + try { + return executeAsync(s3request); + } catch (MinioException e) { + throw new CompletionException(e); + } + }); + } + + /** Execute asynchronously DELETE HTTP request for given parameters. */ + protected CompletableFuture executeDeleteAsync( + BaseArgs args, Http.Headers headers, Http.QueryParameters queryParams) throws MinioException { + return executeAsync( + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.DELETE) + .headers(headers) + .queryParams(queryParams) + .args(args) + .build()) + .thenApply( + response -> { + if (response != null) response.body().close(); + return response; + }); + } + + /** Execute asynchronously POST HTTP request for given parameters. */ + protected CompletableFuture executePostAsync( + BaseArgs args, Http.Headers headers, Http.QueryParameters queryParams, Http.Body body) + throws MinioException { + return executeAsync( + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.POST) + .headers(headers) + .queryParams(queryParams) + .body(body) + .args(args) + .build()); + } + + /** Execute asynchronously PUT HTTP request for given parameters. */ + protected CompletableFuture executePutAsync( + BaseArgs args, Http.Headers headers, Http.QueryParameters queryParams, Http.Body body) + throws MinioException { + return executeAsync( + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.PUT) + .headers(headers) + .queryParams(queryParams) + .body(body) + .args(args) + .build()); + } + + /** Returns region of given bucket either from region cache or set in constructor. */ + protected CompletableFuture getRegion(String bucket, String region) + throws MinioException { + String thisRegion = this.baseUrl.region(); + if (region != null) { + // Error out if region does not match with region passed via constructor. + if (thisRegion != null && !thisRegion.equals(region)) { + throw new IllegalArgumentException( + "region must be " + thisRegion + ", but passed " + region); + } + return CompletableFuture.completedFuture(region); + } + + if (thisRegion != null && !thisRegion.equals("")) { + return CompletableFuture.completedFuture(thisRegion); + } + if (bucket == null || this.provider == null) { + return CompletableFuture.completedFuture(Http.US_EAST_1); + } + region = regionCache.get(bucket); + if (region != null) return CompletableFuture.completedFuture(region); + + return getBucketLocation(GetBucketLocationArgs.builder().bucket(bucket).build()); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////// S3 APIs and their helpers are added here /////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// + + /** Check whether argument is valid or not. */ + protected void checkArgs(BaseArgs args) { + if (args == null) throw new IllegalArgumentException("null arguments"); + + if ((baseUrl.awsDomainSuffix() != null) && (args instanceof BucketArgs)) { + String bucketName = ((BucketArgs) args).bucket(); + if (bucketName.startsWith("xn--") + || bucketName.endsWith("--s3alias") + || bucketName.endsWith("--ol-s3")) { + throw new IllegalArgumentException( + "bucket name '" + + bucketName + + "' must not start with 'xn--' and must not end with '--s3alias' or '--ol-s3'"); + } + } + } + + /** + * Do AbortMultipartUpload + * S3 API asynchronously. + * + * @param args {@link AbortMultipartUploadArgs} object. + * @return {@link CompletableFuture}<{@link AbortMultipartUploadResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture abortMultipartUpload( + AbortMultipartUploadArgs args) throws MinioException { + checkArgs(args); + return executeDeleteAsync(args, null, new Http.QueryParameters(UPLOAD_ID, args.uploadId())) + .thenApply( + response -> { + try { + return new AbortMultipartUploadResponse( + response.headers(), + args.bucket(), + args.location(), + args.object(), + args.uploadId()); + } finally { + response.close(); + } + }); + } + + /** + * Do CompleteMultipartUpload + * S3 API asynchronously. + * + * @param args {@link CompleteMultipartUploadArgs} object. + * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture completeMultipartUpload( + CompleteMultipartUploadArgs args) throws MinioException { + checkArgs(args); + return executePostAsync( + args, + null, + new Http.QueryParameters(UPLOAD_ID, args.uploadId()), + new Http.Body(new CompleteMultipartUpload(args.parts()), null, null, null)) + .thenApply( + response -> { + try { + String bodyContent = response.body().string(); + bodyContent = bodyContent.trim(); + if (!bodyContent.isEmpty()) { + try { + if (Xml.validate(ErrorResponse.class, bodyContent)) { + ErrorResponse errorResponse = Xml.unmarshal(ErrorResponse.class, bodyContent); + throw new CompletionException( + new ErrorResponseException(errorResponse, response, null)); + } + } catch (XmlParserException e) { + // As it is not message, fallback to parse CompleteMultipartUploadOutput + // XML. + } + + try { + CompleteMultipartUploadResult result = + Xml.unmarshal(CompleteMultipartUploadResult.class, bodyContent); + return new ObjectWriteResponse( + response.headers(), + result.bucket(), + result.location(), + result.object(), + result.etag(), + response.header("x-amz-version-id"), + result); + } catch (XmlParserException e) { + // As this CompleteMultipartUpload REST call succeeded, just log it. + Logger.getLogger(BaseS3Client.class.getName()) + .warning( + "S3 service returned unknown XML for CompleteMultipartUpload REST API. " + + bodyContent); + } + } + + return new ObjectWriteResponse( + response.headers(), + args.bucket(), + args.location(), + args.object(), + null, + response.header("x-amz-version-id")); + } catch (IOException e) { + throw new CompletionException(new MinioException(e)); + } finally { + response.close(); + } + }); + } + + public CompletableFuture copyObject(CopyObjectArgs args) + throws MinioException { + checkArgs(args); + args.validateSse(this.baseUrl.isHttps()); + if (args.source().offset() != null || args.source().length() != null) { + throw new IllegalArgumentException("copy object with offset/length is unsupported"); + } + + Http.Headers headers = Http.Headers.merge(args.makeHeaders(), args.source().makeCopyHeaders()); + if (args.metadataDirective() != null) { + headers.put("x-amz-metadata-directive", args.metadataDirective().toString()); + } + if (args.taggingDirective() != null) { + headers.put("x-amz-tagging-directive", args.taggingDirective().toString()); + } + + return executePutAsync(args, headers, null, null) + .thenApply( + response -> { + try { + CopyObjectResult result = + Xml.unmarshal(CopyObjectResult.class, response.body().charStream()); + return new ObjectWriteResponse( + response.headers(), + args.bucket(), + args.region(), + args.object(), + result.etag(), + response.header("x-amz-version-id"), + result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do CreateBucket + * S3 API asynchronously. + * + * @param args {@link CreateBucketArgs} object. + * @return {@link CompletableFuture}<{@link GenericResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture createBucket(CreateBucketArgs args) + throws MinioException { + checkArgs(args); + + String region = args.region(); + String baseUrlRegion = baseUrl.region(); + if (baseUrlRegion != null && !baseUrlRegion.isEmpty()) { + // Error out if region does not match with region passed via constructor. + if (region != null && !region.equals(baseUrlRegion)) { + throw new IllegalArgumentException( + "region must be " + baseUrlRegion + ", but passed " + region); + } + region = baseUrlRegion; + } + if (region == null) { + region = Http.US_EAST_1; + } + + Http.Headers headers = + args.objectLock() ? new Http.Headers("x-amz-bucket-object-lock-enabled", "true") : null; + final String locationConstraint = region; + + CreateBucketConfiguration config = null; + if (locationConstraint.equals(Http.US_EAST_1)) { + config = + new CreateBucketConfiguration( + locationConstraint, args.locationConfig(), args.bucketConfig()); + } + + return executeAsync( + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.PUT) + .headers(headers) + .body(new Http.Body(config, null, null, null)) + .args(args) + .build(), + locationConstraint) + .thenApply( + response -> { + try { + return new GenericResponse( + response.headers(), args.bucket(), args.location(), null); + } finally { + response.close(); + } + }); + } + + /** + * Do CreateMultipartUpload + * S3 API asynchronously. + * + * @param args {@link CreateMultipartUploadArgs} object. + * @return {@link CompletableFuture}<{@link CreateMultipartUploadResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture createMultipartUpload( + CreateMultipartUploadArgs args) throws MinioException { + checkArgs(args); + return executePostAsync(args, args.headers(), new Http.QueryParameters("uploads", ""), null) + .thenApply( + response -> { + try { + InitiateMultipartUploadResult result = + Xml.unmarshal( + InitiateMultipartUploadResult.class, response.body().charStream()); + return new CreateMultipartUploadResponse( + response.headers(), args.bucket(), args.location(), args.object(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do DeleteObjects S3 + * API asynchronously. + * + * @param args {@link DeleteObjectsArgs} object. + * @return {@link CompletableFuture}<{@link DeleteObjectsResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture deleteObjects(DeleteObjectsArgs args) + throws MinioException { + checkArgs(args); + return executePostAsync( + args, + args.bypassGovernanceMode() + ? new Http.Headers("x-amz-bypass-governance-retention", "true") + : null, + new Http.QueryParameters("delete", ""), + new Http.Body(new DeleteRequest(args.objects(), args.quiet()), null, null, null)) + .thenApply( + response -> { + try { + String bodyContent = response.body().string(); + try { + if (Xml.validate(DeleteResult.Error.class, bodyContent)) { + DeleteResult.Error error = Xml.unmarshal(DeleteResult.Error.class, bodyContent); + DeleteResult result = new DeleteResult(error); + return new DeleteObjectsResponse( + response.headers(), args.bucket(), args.region(), result); + } + } catch (XmlParserException e) { + // Ignore this exception as it is not message, + // but parse it as message below. + } + + DeleteResult result = Xml.unmarshal(DeleteResult.class, bodyContent); + return new DeleteObjectsResponse( + response.headers(), args.bucket(), args.region(), result); + } catch (IOException e) { + throw new CompletionException(new MinioException(e)); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do GetBucketLocation + * S3 API asynchronously. + * + * @param args {@link GetBucketLocationArgs} object. + * @return {@link CompletableFuture}<{@link String}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture getBucketLocation(GetBucketLocationArgs args) + throws MinioException { + checkArgs(args); + return executeAsync( + Http.S3Request.builder() + .userAgent(userAgent) + .method(Http.Method.GET) + .args(args) + .queryParams(new Http.QueryParameters("location", null)) + .build(), + Http.US_EAST_1) + .thenApply( + response -> { + String location; + try (ResponseBody body = response.body()) { + LocationConstraint lc = Xml.unmarshal(LocationConstraint.class, body.charStream()); + if (lc.location() == null || lc.location().equals("")) { + location = Http.US_EAST_1; + } else if (lc.location().equals("EU") && this.baseUrl.awsDomainSuffix() != null) { + location = "eu-west-1"; // eu-west-1 is also referred as 'EU'. + } else { + location = lc.location(); + } + } catch (XmlParserException e) { + throw new CompletionException(e); + } + + regionCache.put(args.bucket(), location); + return location; + }); + } + + /** + * Do HeadObject S3 + * API asynchronously. + * + * @param args {@link HeadObjectArgs} object. + * @return {@link CompletableFuture}<{@link HeadObjectResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture headObject(HeadObjectArgs args) + throws MinioException { + checkArgs(args); + args.validateSsec(baseUrl.isHttps()); + return executeHeadAsync( + args, + args.makeHeaders(), + (args.versionId() != null) + ? new Http.QueryParameters("versionId", args.versionId()) + : null) + .thenApply( + response -> + new HeadObjectResponse( + response.headers(), args.bucket(), args.region(), args.object())); + } + + /** + * Do ListBuckets + * S3 API asynchronously. + * + * @param args {@link ListBucketsArgs} object. + * @return {@link CompletableFuture}<{@link ListBucketsResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture listBucketsAPI(ListBucketsArgs args) + throws MinioException { + checkArgs(args); + + Http.QueryParameters queryParams = new Http.QueryParameters(); + if (args.bucketRegion() != null) queryParams.put("bucket-region", args.bucketRegion()); + queryParams.put( + "max-buckets", Integer.toString(args.maxBuckets() > 0 ? args.maxBuckets() : 10000)); + if (args.prefix() != null) queryParams.put("prefix", args.prefix()); + if (args.continuationToken() != null) { + queryParams.put("continuation-token", args.continuationToken()); + } + + return executeGetAsync(args, null, queryParams) + .thenApply( + response -> { + try { + ListAllMyBucketsResult result = + Xml.unmarshal(ListAllMyBucketsResult.class, response.body().charStream()); + return new ListBucketsResponse(response.headers(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do ListMultipartUploads + * S3 API asynchronously. + * + * @param args {@link ListMultipartUploadsArgs} object. + * @return {@link CompletableFuture}<{@link ListMultipartUploadsResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture listMultipartUploads( + ListMultipartUploadsArgs args) throws MinioException { + checkArgs(args); + Http.QueryParameters queryParams = + new Http.QueryParameters( + "uploads", + "", + "delimiter", + (args.delimiter() != null) ? args.delimiter() : "", + "max-uploads", + (args.maxUploads() != null) ? args.maxUploads().toString() : "1000", + "prefix", + (args.prefix() != null) ? args.prefix() : ""); + if (args.encodingType() != null) queryParams.put("encoding-type", args.encodingType()); + if (args.keyMarker() != null) queryParams.put("key-marker", args.keyMarker()); + if (args.uploadIdMarker() != null) queryParams.put("upload-id-marker", args.uploadIdMarker()); + + return executeGetAsync(args, null, queryParams) + .thenApply( + response -> { + try { + ListMultipartUploadsResult result = + Xml.unmarshal(ListMultipartUploadsResult.class, response.body().charStream()); + return new ListMultipartUploadsResponse( + response.headers(), args.bucket(), args.region(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + private Http.QueryParameters getCommonListObjectsQueryParams( + String delimiter, String encodingType, Integer maxKeys, String prefix) { + Http.QueryParameters queryParams = + new Http.QueryParameters( + "delimiter", + (delimiter == null) ? "" : delimiter, + "max-keys", + Integer.toString(maxKeys > 0 ? maxKeys : 1000), + "prefix", + (prefix == null) ? "" : prefix); + if (encodingType != null) queryParams.put("encoding-type", encodingType); + return queryParams; + } + + /** + * Do ListObjects + * version 1 S3 API asynchronously. + * + * @param args {@link ListObjectsV1Args} object. + * @return {@link CompletableFuture}<{@link ListObjectsV1Response}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture listObjectsV1(ListObjectsV1Args args) + throws MinioException { + checkArgs(args); + + Http.QueryParameters queryParams = + getCommonListObjectsQueryParams( + args.delimiter(), args.encodingType(), args.maxKeys(), args.prefix()); + if (args.marker() != null) queryParams.put("marker", args.marker()); + + return executeGetAsync(args, null, queryParams) + .thenApply( + response -> { + try { + ListBucketResultV1 result = + Xml.unmarshal(ListBucketResultV1.class, response.body().charStream()); + return new ListObjectsV1Response( + response.headers(), args.bucket(), args.region(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do ListObjects + * version 2 S3 API asynchronously. + * + * @param args {@link ListObjectsV2Args} object. + * @return {@link CompletableFuture}<{@link ListObjectsV2Response}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture listObjectsV2(ListObjectsV2Args args) + throws MinioException { + checkArgs(args); + + Http.QueryParameters queryParams = + getCommonListObjectsQueryParams( + args.delimiter(), args.encodingType(), args.maxKeys(), args.prefix()); + if (args.startAfter() != null) queryParams.put("start-after", args.startAfter()); + if (args.continuationToken() != null) + queryParams.put("continuation-token", args.continuationToken()); + if (args.fetchOwner()) queryParams.put("fetch-owner", "true"); + if (args.includeUserMetadata()) queryParams.put("metadata", "true"); + queryParams.put("list-type", "2"); + + return executeGetAsync(args, null, queryParams) + .thenApply( + response -> { + try { + ListBucketResultV2 result = + Xml.unmarshal(ListBucketResultV2.class, response.body().charStream()); + return new ListObjectsV2Response( + response.headers(), args.bucket(), args.region(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do ListObjectVersions + * API asynchronously. + * + * @param args {@link ListObjectVersionsArgs} object. + * @return {@link CompletableFuture}<{@link ListObjectVersionsResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture listObjectVersions( + ListObjectVersionsArgs args) throws MinioException { + checkArgs(args); + + Http.QueryParameters queryParams = + getCommonListObjectsQueryParams( + args.delimiter(), args.encodingType(), args.maxKeys(), args.prefix()); + if (args.keyMarker() != null) queryParams.put("key-marker", args.keyMarker()); + if (args.versionIdMarker() != null) { + queryParams.put("version-id-marker", args.versionIdMarker()); + } + queryParams.put("versions", ""); + + return executeGetAsync(args, null, queryParams) + .thenApply( + response -> { + try { + ListVersionsResult result = + Xml.unmarshal(ListVersionsResult.class, response.body().charStream()); + return new ListObjectVersionsResponse( + response.headers(), args.bucket(), args.region(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + /** + * Do ListParts S3 + * API asynchronously. + * + * @param args {@link ListPartsArgs} object. + * @return {@link CompletableFuture}<{@link ListPartsResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture listParts(ListPartsArgs args) throws MinioException { + Http.QueryParameters queryParams = + new Http.QueryParameters( + UPLOAD_ID, + args.uploadId(), + "max-parts", + (args.maxParts() != null) ? args.maxParts().toString() : "1000"); + if (args.partNumberMarker() != null) { + queryParams.put("part-number-marker", args.partNumberMarker().toString()); + } + + return executeGetAsync(args, null, queryParams) + .thenApply( + response -> { + try { + ListPartsResult result = + Xml.unmarshal(ListPartsResult.class, response.body().charStream()); + return new ListPartsResponse( + response.headers(), args.bucket(), args.region(), args.object(), result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } + + private Object[] createBody(PutObjectAPIBaseArgs args, MediaType contentType) + throws MinioException { + Http.Headers headers = new Http.Headers(args.headers()); + String sha256HexString = headers.getFirst(Http.Headers.X_AMZ_CONTENT_SHA256); + String sha256Base64String = headers.getFirst(Http.Headers.X_AMZ_CHECKSUM_SHA256); + boolean checksumHeader = headers.namePrefixAny("x-amz-checksum-"); + String md5Hash = headers.getFirst(Http.Headers.CONTENT_MD5); + + if (sha256HexString == null && sha256Base64String == null) { + if (!baseUrl.isHttps()) { + Checksum.Hasher hasher = Checksum.Algorithm.SHA256.hasher(); + Map hashers = new HashMap<>(); + hashers.put(Checksum.Algorithm.SHA256, hasher); + if (args.file() != null) { + Checksum.update(hashers, args.file(), args.length()); + } else if (args.buffer() != null) { + Checksum.update(hashers, args.buffer()); + } else if (args.data() != null) { + Checksum.update(hashers, args.data(), args.length().intValue()); + } + byte[] sum = hasher.sum(); + sha256HexString = Checksum.hexString(sum); + } else { + sha256HexString = Checksum.UNSIGNED_PAYLOAD; + } + headers.put(Http.Headers.X_AMZ_CONTENT_SHA256, sha256HexString); + } + + if (sha256HexString == null && sha256Base64String != null) { + sha256HexString = Checksum.UNSIGNED_PAYLOAD; + if (!baseUrl.isHttps()) { + sha256HexString = Checksum.hexString(Checksum.base64StringToSum(sha256Base64String)); + } + headers.put(Http.Headers.X_AMZ_CONTENT_SHA256, sha256HexString); + } + + if (sha256HexString != null + && sha256Base64String == null + && !checksumHeader + && md5Hash == null) { + if (Checksum.UNSIGNED_PAYLOAD.equals(sha256HexString)) { + Checksum.Hasher hasher = Checksum.Algorithm.CRC32C.hasher(); + Map hashers = new HashMap<>(); + hashers.put(Checksum.Algorithm.CRC32C, hasher); + if (args.file() != null) { + Checksum.update(hashers, args.file(), args.length()); + } else if (args.buffer() != null) { + Checksum.update(hashers, args.buffer()); + } else if (args.data() != null) { + Checksum.update(hashers, args.data(), args.length().intValue()); + } + byte[] sum = hasher.sum(); + headers.put(Checksum.Algorithm.CRC32C.header(), Checksum.base64String(sum)); + headers.put( + Http.Headers.X_AMZ_SDK_CHECKSUM_ALGORITHM, Checksum.Algorithm.CRC32C.toString()); + } else { + sha256Base64String = Checksum.base64String(Checksum.hexStringToSum(sha256HexString)); + headers.put(Http.Headers.X_AMZ_CHECKSUM_SHA256, sha256Base64String); + headers.put( + Http.Headers.X_AMZ_SDK_CHECKSUM_ALGORITHM, Checksum.Algorithm.SHA256.toString()); + } + } + + Http.Body body = null; + if (args.file() != null) { + body = new Http.Body(args.file(), args.length(), contentType, sha256HexString, md5Hash); + } else if (args.buffer() != null) { + body = new Http.Body(args.buffer(), contentType, sha256HexString, md5Hash); + } else if (args.data() != null) { + body = + new Http.Body( + args.data(), args.length().intValue(), contentType, sha256HexString, md5Hash); + } else { + throw new InternalException("unknown body found; this should not happen"); + } + + return new Object[] {body, headers}; + } + + /** + * Do PutObject S3 + * API asynchronously. + * + * @param args {@link PutObjectAPIArgs} object. + * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture putObject(PutObjectAPIArgs args) + throws MinioException { + checkArgs(args); + + Object[] result = createBody(args, args.contentType()); + Http.Body body = (Http.Body) result[0]; + Http.Headers headers = (Http.Headers) result[1]; + return executePutAsync(args, headers, null, body) + .thenApply( + response -> { + try { + return new ObjectWriteResponse( + response.headers(), + args.bucket(), + args.region(), + args.object(), + response.header("ETag").replaceAll("\"", ""), + response.header("x-amz-version-id")); + } finally { + response.close(); + } + }); + } + + /** + * Do UploadPart S3 + * API asynchronously. + * + * @param args {@link UploadPartArgs} object. + * @return {@link CompletableFuture}<{@link UploadPartResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture uploadPart(UploadPartArgs args) + throws MinioException { + checkArgs(args); + + Object[] result = createBody(args, null); + Http.Body body = (Http.Body) result[0]; + Http.Headers headers = (Http.Headers) result[1]; + return executePutAsync( + args, + headers, + new Http.QueryParameters( + "partNumber", Integer.toString(args.partNumber()), "uploadId", args.uploadId()), + body) + .thenApply( + response -> { + try { + return new UploadPartResponse( + response.headers(), + args.bucket(), + args.region(), + args.object(), + args.uploadId(), + args.partNumber(), + response.header("ETag").replaceAll("\"", "")); + } finally { + response.close(); + } + }); + } + + /** + * Do UploadPartCopy + * S3 API. + * + * @param args {@link UploadPartCopyArgs} object. + * @return {@link CompletableFuture}<{@link UploadPartCopyResponse}> object. + * @throws MinioException thrown to indicate SDK exception. + */ + public CompletableFuture uploadPartCopy(UploadPartCopyArgs args) + throws MinioException { + checkArgs(args); + return executePutAsync( + args, + args.headers(), + new Http.QueryParameters( + "partNumber", Integer.toString(args.partNumber()), "uploadId", args.uploadId()), + null) + .thenApply( + response -> { + try { + CopyPartResult result = + Xml.unmarshal(CopyPartResult.class, response.body().charStream()); + return new UploadPartCopyResponse( + response.headers(), + args.bucket(), + args.region(), + args.object(), + args.uploadId(), + args.partNumber(), + result); + } catch (XmlParserException e) { + throw new CompletionException(e); + } finally { + response.close(); + } + }); + } +} diff --git a/api/src/main/java/io/minio/BucketArgs.java b/api/src/main/java/io/minio/BucketArgs.java index c50bcdfda..2306ef94e 100644 --- a/api/src/main/java/io/minio/BucketArgs.java +++ b/api/src/main/java/io/minio/BucketArgs.java @@ -16,16 +16,38 @@ package io.minio; -import io.minio.http.HttpUtils; -import io.minio.org.apache.commons.validator.routines.InetAddressValidator; import java.util.Objects; import java.util.regex.Pattern; -/** Base argument class holds bucket name and region. */ +/** + * Common arguments of {@link BucketExistsArgs}, {@link CreateBucketBaseArgs}, {@link + * DeleteBucketCorsArgs}, {@link DeleteBucketEncryptionArgs}, {@link DeleteBucketLifecycleArgs}, + * {@link DeleteBucketNotificationArgs}, {@link DeleteBucketPolicyArgs}, {@link + * DeleteBucketReplicationArgs}, {@link DeleteBucketTagsArgs}, {@link + * DeleteObjectLockConfigurationArgs}, {@link DeleteObjectsArgs}, {@link GetBucketCorsArgs}, {@link + * GetBucketEncryptionArgs}, {@link GetBucketLifecycleArgs}, {@link GetBucketLocationArgs}, {@link + * GetBucketNotificationArgs}, {@link GetBucketPolicyArgs}, {@link GetBucketReplicationArgs}, {@link + * GetBucketTagsArgs}, {@link GetBucketVersioningArgs}, {@link GetObjectLockConfigurationArgs}, + * {@link ListenBucketNotificationArgs}, {@link ListMultipartUploadsArgs}, {@link ListObjectsArgs}, + * {@link ListObjectsV1Args}, {@link ListObjectsV2Args}, {@link ListObjectVersionsArgs}, {@link + * ListPartsArgs}, {@link ObjectArgs}, {@link PutObjectFanOutArgs}, {@link RemoveBucketArgs}, {@link + * RemoveObjectsArgs}, {@link SetBucketCorsArgs}, {@link SetBucketEncryptionArgs}, {@link + * SetBucketLifecycleArgs}, {@link SetBucketNotificationArgs}, {@link SetBucketPolicyArgs}, {@link + * SetBucketReplicationArgs}, {@link SetBucketTagsArgs}, {@link SetBucketVersioningArgs} and {@link + * SetObjectLockConfigurationArgs}. + */ public abstract class BucketArgs extends BaseArgs { protected String bucketName; protected String region; + protected BucketArgs() {} + + protected BucketArgs(BucketArgs args) { + super(args); + this.bucketName = args.bucketName; + this.region = args.region; + } + public String bucket() { return bucketName; } @@ -34,7 +56,7 @@ public String region() { return region; } - /** Base argument builder class for {@link BucketArgs}. */ + /** Builder of {@link BucketArgs}. */ public abstract static class Builder, A extends BucketArgs> extends BaseArgs.Builder { private static final Pattern BUCKET_NAME_REGEX = @@ -42,7 +64,7 @@ public abstract static class Builder, A extends BucketAr protected boolean skipValidation = false; protected void validateBucketName(String name) { - validateNotNull(name, "bucket name"); + Utils.validateNotNull(name, "bucket name"); if (skipValidation) { return; } @@ -55,7 +77,7 @@ protected void validateBucketName(String name) { + "https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html"); } - if (InetAddressValidator.getInstance().isValidInet4Address(name)) { + if (Utils.isValidIPv4(name)) { throw new IllegalArgumentException( "bucket name '" + name + "' must not be formatted as an IP address"); } @@ -67,7 +89,7 @@ protected void validateBucketName(String name) { } private void validateRegion(String region) { - if (!skipValidation && region != null && !HttpUtils.REGION_REGEX.matcher(region).find()) { + if (!skipValidation && region != null && !Utils.REGION_REGEX.matcher(region).find()) { throw new IllegalArgumentException("invalid region " + region); } } diff --git a/api/src/main/java/io/minio/BucketExistsArgs.java b/api/src/main/java/io/minio/BucketExistsArgs.java index 86b19eb32..2dd41a4ea 100644 --- a/api/src/main/java/io/minio/BucketExistsArgs.java +++ b/api/src/main/java/io/minio/BucketExistsArgs.java @@ -16,12 +16,12 @@ package io.minio; -/** Argument class of {@link MinioAsyncClient#bucketExists} and {@link MinioClient#bucketExists}. */ +/** Arguments of {@link MinioAsyncClient#bucketExists} and {@link MinioClient#bucketExists}. */ public class BucketExistsArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link BucketExistsArgs}. */ + /** Builder of {@link BucketExistsArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/ByteBuffer.java b/api/src/main/java/io/minio/ByteBuffer.java new file mode 100644 index 000000000..98fb8d6f9 --- /dev/null +++ b/api/src/main/java/io/minio/ByteBuffer.java @@ -0,0 +1,129 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2025 MinIO, 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 io.minio; + +import io.minio.errors.MinioException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.SequenceInputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** {@link OutputStream} compatible byte buffer to store maximum 5GiB. */ +public class ByteBuffer extends OutputStream { + private static class Buffer extends ByteArrayOutputStream { + public InputStream inputStream() { + return (count > 0) ? new ByteArrayInputStream(buf, 0, count) : null; + } + } + + private static final int CHUNK_SIZE = Integer.MAX_VALUE; + private final long totalSize; + private final List buffers = new ArrayList<>(); + private int index = 0; + private long writtenBytes = 0; + private boolean isClosed = false; + + public ByteBuffer(long totalSize) { + if (totalSize > ObjectWriteArgs.MAX_PART_SIZE) { + throw new IllegalArgumentException("Total size cannot exceed 5GiB"); + } + this.totalSize = totalSize; + } + + private void updateIndex() { + if (buffers.isEmpty()) { + index = 0; + buffers.add(new Buffer()); + } else if (writtenBytes >= (long) (index + 1) * CHUNK_SIZE) { + index++; + if (index > buffers.size() - 1) buffers.add(new Buffer()); + } + } + + @Override + public void write(int b) throws IOException { + if (isClosed) throw new IOException("Stream is closed"); + if (writtenBytes >= totalSize) throw new IOException("Exceeded total size limit"); + updateIndex(); + buffers.get(index).write(b); + writtenBytes++; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (isClosed) throw new IOException("Stream is closed"); + if (len > (totalSize - writtenBytes)) throw new IOException("Exceeded total size limit"); + int remaining = len; + while (remaining > 0) { + updateIndex(); + Buffer currentBuffer = buffers.get(index); + int bytesToWrite = Math.min(remaining, CHUNK_SIZE - currentBuffer.size()); + currentBuffer.write(b, off + (len - remaining), bytesToWrite); + writtenBytes += bytesToWrite; + remaining -= bytesToWrite; + } + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + public long length() { + return writtenBytes; + } + + public long size() { + return totalSize; + } + + public void reset() throws MinioException { + if (isClosed) throw new MinioException("Cannot reset a closed stream"); + writtenBytes = 0; + index = 0; + for (Buffer buffer : buffers) buffer.reset(); + } + + public void close() throws IOException { + if (!isClosed) { + isClosed = true; + buffers.clear(); + } + } + + public InputStream inputStream() { + List streams = new ArrayList<>(); + for (Buffer buffer : buffers) { + InputStream stream = buffer.inputStream(); + if (stream != null) streams.add(stream); + } + switch (streams.size()) { + case 0: + return new ByteArrayInputStream(Utils.EMPTY_BODY); + case 1: + return streams.get(0); + default: + return new SequenceInputStream(Collections.enumeration(streams)); + } + } +} diff --git a/api/src/main/java/io/minio/ByteBufferPool.java b/api/src/main/java/io/minio/ByteBufferPool.java new file mode 100644 index 000000000..7f2bee6e3 --- /dev/null +++ b/api/src/main/java/io/minio/ByteBufferPool.java @@ -0,0 +1,59 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2025 MinIO, 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 io.minio; + +import io.minio.errors.MinioException; +import java.lang.ref.SoftReference; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** Pool of {@link ByteBuffer} to be reused. */ +public class ByteBufferPool { + private final ConcurrentLinkedQueue> pool = + new ConcurrentLinkedQueue<>(); + private final int maxSize; + private final long bufferSize; + + public ByteBufferPool(int maxSize, long bufferSize) { + this.maxSize = maxSize; + this.bufferSize = bufferSize; + } + + public ByteBuffer get() { + while (!pool.isEmpty()) { + SoftReference ref = pool.poll(); + if (ref != null) { + ByteBuffer buffer = ref.get(); + if (buffer != null) { + return buffer; + } + // SoftReference cleared + } + } + return new ByteBuffer(bufferSize); + } + + public void put(ByteBuffer buffer) throws MinioException { + if (buffer == null) return; + + buffer.reset(); // Reset buffer before reuse + + if (pool.size() < maxSize) { + pool.offer(new SoftReference<>(buffer)); + } + } +} diff --git a/api/src/main/java/io/minio/ByteBufferStream.java b/api/src/main/java/io/minio/ByteBufferStream.java deleted file mode 100644 index 8dd8ca1f1..000000000 --- a/api/src/main/java/io/minio/ByteBufferStream.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2021 MinIO, 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 io.minio; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; - -/** ByteArrayOutputStream exposes underneath buffer as input stream. */ -class ByteBufferStream extends ByteArrayOutputStream { - public ByteBufferStream() { - super(); - } - - public InputStream inputStream() { - return new ByteArrayInputStream(this.buf, 0, this.count); - } -} diff --git a/api/src/main/java/io/minio/Checksum.java b/api/src/main/java/io/minio/Checksum.java new file mode 100644 index 000000000..1722c981b --- /dev/null +++ b/api/src/main/java/io/minio/Checksum.java @@ -0,0 +1,537 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import io.minio.errors.MinioException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** Collection of checksum algorithms. */ +public class Checksum { + // MD5 hash of zero length byte array. + public static final String ZERO_MD5_HASH = "1B2M2Y8AsgTpgAmY7PhCfg=="; + // SHA-256 hash of zero length byte array. + public static final String ZERO_SHA256_HASH = + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + public static final String UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD"; + + public static String base64String(byte[] sum) { + return Base64.getEncoder().encodeToString(sum); + } + + public static byte[] base64StringToSum(String sum) { + return Base64.getDecoder().decode(sum); + } + + public static String hexString(byte[] sum) { + StringBuilder builder = new StringBuilder(); + for (byte b : sum) builder.append(String.format("%02x", b)); + return builder.toString(); + } + + public static byte[] hexStringToSum(String sum) { + byte[] data = new byte[sum.length() / 2]; + for (int i = 0; i < sum.length(); i += 2) { + data[i / 2] = + (byte) + ((Character.digit(sum.charAt(i), 16) << 4) + Character.digit(sum.charAt(i + 1), 16)); + } + return data; + } + + public static Map newHasherMap(Algorithm[] algorithms) throws MinioException { + Map hashers = null; + if (algorithms != null) { + for (Checksum.Algorithm algorithm : algorithms) { + if (algorithm != null) { + if (hashers == null) hashers = new HashMap<>(); + if (!hashers.containsKey(algorithm)) { + hashers.put(algorithm, algorithm.hasher()); + } + } + } + } + return (hashers == null || hashers.size() == 0) ? null : hashers; + } + + public static void update(Map hashers, byte[] data, int length) { + if (hashers == null || hashers.size() == 0) return; + for (Map.Entry entry : hashers.entrySet()) { + entry.getValue().update(data, 0, length); + } + } + + private static void update( + Map hashers, ByteBuffer buffer, RandomAccessFile file, Long size) + throws MinioException { + if (hashers == null || hashers.size() == 0) return; + + InputStream stream = null; + if (buffer != null) { + stream = buffer.inputStream(); + size = buffer.length(); + } + + byte[] buf16k = new byte[16384]; + long bytesRead = 0; + while (bytesRead != size) { + try { + int length = (int) Math.min(size - bytesRead, buf16k.length); + int n = file != null ? file.read(buf16k, 0, length) : stream.read(buf16k, 0, length); + if (n < 0) throw new MinioException("unexpected EOF"); + if (n != 0) { + bytesRead += n; + update(hashers, buf16k, n); + } + } catch (IOException e) { + throw new MinioException(e); + } + } + } + + public static void update(Map hashers, RandomAccessFile file, long size) + throws MinioException { + update(hashers, null, file, size); + } + + public static void update(Map hashers, ByteBuffer buffer) + throws MinioException { + update(hashers, buffer, null, null); + } + + public static Http.Headers makeHeaders( + Map hashers, boolean computeSha256, boolean sha256Algorithm) { + if (hashers == null) return null; + + Http.Headers checksumHeaders = new Http.Headers(); + for (Map.Entry entry : hashers.entrySet()) { + byte[] sum = entry.getValue().sum(); + if (entry.getKey() == Checksum.Algorithm.SHA256) { + if (computeSha256) { + checksumHeaders.put(Http.Headers.X_AMZ_CONTENT_SHA256, Checksum.hexString(sum)); + } + if (!sha256Algorithm) continue; + } + checksumHeaders.put("x-amz-sdk-checksum-algorithm", entry.getKey().toString()); + checksumHeaders.put(entry.getKey().header(), Checksum.base64String(sum)); + } + + return checksumHeaders; + } + + /** Algorithm type. */ + public static enum Type { + COMPOSITE, + FULL_OBJECT; + } + + /** Checksum algorithm. */ + public static enum Algorithm { + CRC32, + CRC32C, + CRC64NVME, + SHA1, + SHA256, + MD5; + + @Override + public String toString() { + return name().toLowerCase(Locale.US); + } + + public String header() { + if (this == MD5) return Http.Headers.CONTENT_MD5; + return "x-amz-checksum-" + name().toLowerCase(Locale.US); + } + + public boolean fullObjectSupport() { + return this == CRC32 || this == CRC32C || this == CRC64NVME; + } + + public boolean compositeSupport() { + return this == CRC32 || this == CRC32C || this == SHA1 || this == SHA256; + } + + public void validate(Type type) { + if (!(compositeSupport() && type == Type.COMPOSITE + || fullObjectSupport() && type == Type.FULL_OBJECT)) { + throw new IllegalArgumentException( + "algorithm " + name() + " does not support " + type + " type"); + } + } + + public Hasher hasher() throws MinioException { + if (this == CRC32) return new CRC32(); + if (this == CRC32C) return new CRC32C(); + if (this == CRC64NVME) return new CRC64NVME(); + if (this == SHA1) return new SHA1(); + if (this == SHA256) return new SHA256(); + if (this == MD5) return new MD5(); + return null; + } + } + + /** {@link OutputStream} compatible checksum hasher. */ + public abstract static class Hasher extends OutputStream { + public abstract void update(byte[] b, int off, int len); + + public abstract byte[] sum(); + + public abstract void reset(); + + public void update(byte[] b) { + update(b, 0, b.length); + } + + @Override + public void write(int b) { + update(new byte[] {(byte) b}); + } + + @Override + public void write(byte[] b) { + update(b); + } + + @Override + public void write(byte[] b, int off, int len) { + update(b, off, len); + } + } + + /** CRC32 checksum {@link Hasher}. */ + public static class CRC32 extends Hasher { + private java.util.zip.CRC32 hasher; + + public CRC32() { + hasher = new java.util.zip.CRC32(); + } + + @Override + public void update(byte[] b, int off, int len) { + hasher.update(b, off, len); + } + + @Override + public void update(byte[] b) { + hasher.update(b); + } + + @Override + public byte[] sum() { + int value = (int) hasher.getValue(); + return new byte[] { + (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value + }; + } + + @Override + public void reset() { + hasher.reset(); + } + + @Override + public String toString() { + return "CRC32{" + hexString(sum()) + "}"; + } + } + + /** CRC32C checksum {@link Hasher}. */ + public static class CRC32C extends Hasher implements java.util.zip.Checksum { + private static final int[] CRC32C_TABLE = new int[256]; + private int crc = 0xFFFFFFFF; + + static { + for (int i = 0; i < 256; i++) { + int crc = i; + for (int j = 0; j < 8; j++) { + crc = (crc >>> 1) ^ ((crc & 1) != 0 ? 0x82F63B78 : 0); + } + CRC32C_TABLE[i] = crc; + } + } + + @Override + public void update(int b) { + crc = CRC32C_TABLE[(crc ^ b) & 0xFF] ^ (crc >>> 8); + } + + @Override + public void update(byte[] b, int off, int len) { + for (int i = off; i < off + len; i++) { + update(b[i]); + } + } + + @Override + public long getValue() { + return (crc ^ 0xFFFFFFFFL) & 0xFFFFFFFFL; + } + + @Override + public void reset() { + crc = 0xFFFFFFFF; + } + + @Override + public byte[] sum() { + int value = (int) this.getValue(); + return new byte[] { + (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value + }; + } + + @Override + public String toString() { + return "CRC32C{" + hexString(sum()) + "}"; + } + } + + /** CRC64NVME checksum {@link Hasher} copied from https://github.com/minio/crc64nvme. */ + public static class CRC64NVME extends Hasher implements java.util.zip.Checksum { + private static final long[] CRC64_TABLE = new long[256]; + private static final long[][] SLICING8_TABLE_NVME = new long[8][256]; + + static { + long polynomial = 0x9A6C9329AC4BC9B5L; + for (int i = 0; i < 256; i++) { + long crc = i; + for (int j = 0; j < 8; j++) { + if ((crc & 1) == 1) { + crc = (crc >>> 1) ^ polynomial; + } else { + crc >>>= 1; + } + } + CRC64_TABLE[i] = crc; + } + + SLICING8_TABLE_NVME[0] = CRC64_TABLE; + for (int i = 0; i < 256; i++) { + long crc = CRC64_TABLE[i]; + for (int j = 1; j < 8; j++) { + crc = CRC64_TABLE[(int) crc & 0xFF] ^ (crc >>> 8); + SLICING8_TABLE_NVME[j][i] = crc; + } + } + } + + private long crc = 0; + + public CRC64NVME() {} + + @Override + public void update(byte[] p, int off, int len) { + java.nio.ByteBuffer byteBuffer = java.nio.ByteBuffer.wrap(p, off, len); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + int offset = byteBuffer.position(); + + crc = ~crc; + while (p.length >= 64 && (p.length - offset) > 8) { + long value = byteBuffer.getLong(); + crc ^= value; + crc = + SLICING8_TABLE_NVME[7][(int) (crc & 0xFF)] + ^ SLICING8_TABLE_NVME[6][(int) ((crc >>> 8) & 0xFF)] + ^ SLICING8_TABLE_NVME[5][(int) ((crc >>> 16) & 0xFF)] + ^ SLICING8_TABLE_NVME[4][(int) ((crc >>> 24) & 0xFF)] + ^ SLICING8_TABLE_NVME[3][(int) ((crc >>> 32) & 0xFF)] + ^ SLICING8_TABLE_NVME[2][(int) ((crc >>> 40) & 0xFF)] + ^ SLICING8_TABLE_NVME[1][(int) ((crc >>> 48) & 0xFF)] + ^ SLICING8_TABLE_NVME[0][(int) (crc >>> 56)]; + offset = byteBuffer.position(); + } + + for (; offset < len; offset++) { + crc = CRC64_TABLE[(int) ((crc ^ (long) p[offset]) & 0xFF)] ^ (crc >>> 8); + } + + crc = ~crc; + } + + @Override + public void update(int b) { + update(new byte[] {(byte) b}, 0, 1); + } + + @Override + public long getValue() { + return crc; + } + + @Override + public void reset() { + crc = 0; + } + + @Override + public byte[] sum() { + long value = this.getValue(); + return new byte[] { + (byte) (value >>> 56), + (byte) (value >>> 48), + (byte) (value >>> 40), + (byte) (value >>> 32), + (byte) (value >>> 24), + (byte) (value >>> 16), + (byte) (value >>> 8), + (byte) value + }; + } + + @Override + public String toString() { + return "CRC64NVME{" + hexString(sum()) + "}"; + } + } + + /** SHA1 checksum {@link Hasher}. */ + public static class SHA1 extends Hasher { + MessageDigest hasher; + + public SHA1() throws MinioException { + try { + this.hasher = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + throw new MinioException(e); + } + } + + public void update(byte[] b, int off, int len) { + hasher.update(b, off, len); + } + + public void update(byte[] b) { + hasher.update(b); + } + + public byte[] sum() { + return hasher.digest(); + } + + public void reset() { + hasher.reset(); + } + + @Override + public String toString() { + return "SHA1{" + hexString(sum()) + "}"; + } + } + + /** SHA256 checksum {@link Hasher}. */ + public static class SHA256 extends Hasher { + MessageDigest hasher; + + public SHA256() throws MinioException { + try { + this.hasher = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new MinioException(e); + } + } + + public void update(byte[] b, int off, int len) { + hasher.update(b, off, len); + } + + public void update(byte[] b) { + hasher.update(b); + } + + public byte[] sum() { + return hasher.digest(); + } + + public void reset() { + hasher.reset(); + } + + @Override + public String toString() { + return "SHA256{" + hexString(sum()) + "}"; + } + + public static byte[] sum(byte[] b, int off, int len) throws MinioException { + SHA256 sha256 = new SHA256(); + sha256.update(b, off, len); + return sha256.sum(); + } + + public static byte[] sum(byte[] b) throws MinioException { + return sum(b, 0, b.length); + } + + public static byte[] sum(String value) throws MinioException { + return sum(value.getBytes(StandardCharsets.UTF_8)); + } + } + + /** MD5 checksum {@link Hasher}. */ + public static class MD5 extends Hasher { + MessageDigest hasher; + + public MD5() throws MinioException { + try { + this.hasher = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new MinioException(e); + } + } + + public void update(byte[] b, int off, int len) { + hasher.update(b, off, len); + } + + public void update(byte[] b) { + hasher.update(b); + } + + public byte[] sum() { + return hasher.digest(); + } + + public void reset() { + hasher.reset(); + } + + @Override + public String toString() { + return "MD5{" + base64String(sum()) + "}"; + } + + public static byte[] sum(byte[] b, int off, int len) throws MinioException { + MD5 md5 = new MD5(); + md5.update(b, off, len); + return md5.sum(); + } + + public static byte[] sum(byte[] b) throws MinioException { + return sum(b, 0, b.length); + } + } +} diff --git a/api/src/main/java/io/minio/CompleteMultipartUploadArgs.java b/api/src/main/java/io/minio/CompleteMultipartUploadArgs.java new file mode 100644 index 000000000..824ea42d1 --- /dev/null +++ b/api/src/main/java/io/minio/CompleteMultipartUploadArgs.java @@ -0,0 +1,90 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import io.minio.messages.Part; +import java.util.Arrays; +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#completeMultipartUpload}. */ +public class CompleteMultipartUploadArgs extends ObjectArgs { + private String uploadId; + private Part[] parts; + + protected CompleteMultipartUploadArgs() {} + + public CompleteMultipartUploadArgs(ComposeObjectArgs args, String uploadId, Part[] parts) { + super(args); + this.uploadId = uploadId; + this.parts = parts; + } + + public CompleteMultipartUploadArgs(PutObjectBaseArgs args, String uploadId, Part[] parts) { + super(args); + this.uploadId = uploadId; + this.parts = parts; + } + + public String uploadId() { + return uploadId; + } + + public Part[] parts() { + return parts; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link CompleteMultipartUploadArgs}. */ + public static final class Builder + extends ObjectArgs.Builder { + @Override + protected void validate(CompleteMultipartUploadArgs args) { + super.validate(args); + Utils.validateNotEmptyString(args.uploadId, "upload ID"); + Utils.validateNotNull(args.parts, "parts"); + } + + public Builder uploadId(String uploadId) { + Utils.validateNotEmptyString(uploadId, "upload ID"); + operations.add(args -> args.uploadId = uploadId); + return this; + } + + public Builder parts(Part[] parts) { + Utils.validateNotNull(parts, "parts"); + operations.add(args -> args.parts = parts); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CompleteMultipartUploadArgs)) return false; + if (!super.equals(o)) return false; + CompleteMultipartUploadArgs that = (CompleteMultipartUploadArgs) o; + return Objects.equals(uploadId, that.uploadId) && Arrays.equals(parts, that.parts); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), uploadId, parts); + } +} diff --git a/api/src/main/java/io/minio/ComposeObjectArgs.java b/api/src/main/java/io/minio/ComposeObjectArgs.java index 8f0c42905..0a4ac54d3 100644 --- a/api/src/main/java/io/minio/ComposeObjectArgs.java +++ b/api/src/main/java/io/minio/ComposeObjectArgs.java @@ -16,36 +16,27 @@ package io.minio; -import java.util.LinkedList; +import java.util.Collections; import java.util.List; import java.util.Objects; -import okhttp3.HttpUrl; -/** - * Argument class of {@link MinioAsyncClient#composeObject} and {@link MinioClient#composeObject}. - */ +/** Arguments of {@link MinioAsyncClient#composeObject} and {@link MinioClient#composeObject}. */ public class ComposeObjectArgs extends ObjectWriteArgs { - List sources; + List sources; protected ComposeObjectArgs() {} + public ComposeObjectArgs(ComposeObjectArgs args, List sources) { + super(args); + this.sources = sources; + } + public ComposeObjectArgs(CopyObjectArgs args) { - this.extraHeaders = args.extraHeaders; - this.extraQueryParams = args.extraQueryParams; - this.bucketName = args.bucketName; - this.region = args.region; - this.objectName = args.objectName; - this.headers = args.headers; - this.userMetadata = args.userMetadata; - this.sse = args.sse; - this.tags = args.tags; - this.retention = args.retention; - this.legalHold = args.legalHold; - this.sources = new LinkedList<>(); - this.sources.add(new ComposeSource(args.source())); + super(args); + this.sources = Collections.singletonList(args.source()); } - public List sources() { + public List sources() { return sources; } @@ -54,18 +45,18 @@ public static Builder builder() { } @Override - public void validateSse(HttpUrl url) { - super.validateSse(url); - for (ComposeSource source : sources) { - source.validateSsec(url); + public void validateSse(boolean isHttps) { + super.validateSse(isHttps); + for (SourceObject source : sources) { + source.validateSsec(isHttps); } } - /** Argument builder of {@link ComposeObjectArgs}. */ + /** Builder of {@link ComposeObjectArgs}. */ public static final class Builder extends ObjectWriteArgs.Builder { - private void validateSources(List sources) { + private void validateSources(List sources) { if (sources == null || sources.isEmpty()) { - throw new IllegalArgumentException("compose sources cannot be empty"); + throw new IllegalArgumentException("source objects cannot be empty"); } } @@ -75,7 +66,7 @@ protected void validate(ComposeObjectArgs args) { validateSources(args.sources); } - public Builder sources(List sources) { + public Builder sources(List sources) { validateSources(sources); operations.add(args -> args.sources = sources); return this; diff --git a/api/src/main/java/io/minio/ComposeSource.java b/api/src/main/java/io/minio/ComposeSource.java deleted file mode 100644 index a9449d3f1..000000000 --- a/api/src/main/java/io/minio/ComposeSource.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2019 MinIO, 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 io.minio; - -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import io.minio.errors.InternalException; -import java.util.Objects; - -/** A source object defintion for {@link ComposeObjectArgs}. */ -public class ComposeSource extends ObjectConditionalReadArgs { - private Long objectSize = null; - private Multimap headers = null; - - protected ComposeSource() {} - - public ComposeSource(ObjectConditionalReadArgs args) { - this.extraHeaders = args.extraHeaders; - this.extraQueryParams = args.extraQueryParams; - this.bucketName = args.bucketName; - this.region = args.region; - this.objectName = args.objectName; - this.versionId = args.versionId; - this.ssec = args.ssec; - this.offset = args.offset; - this.length = args.length; - this.matchETag = args.matchETag; - this.notMatchETag = args.notMatchETag; - this.modifiedSince = args.modifiedSince; - this.unmodifiedSince = args.unmodifiedSince; - } - - private void throwException(long objectsize, long arg, String argName) { - StringBuilder builder = - new StringBuilder().append("source ").append(bucketName).append("/").append(objectName); - - if (versionId != null) { - builder.append("?versionId=").append(versionId); - } - - builder - .append(": ") - .append(argName) - .append(" ") - .append(arg) - .append(" is beyond object size ") - .append(objectSize); - - throw new IllegalArgumentException(builder.toString()); - } - - private void validateSize(long objectSize) { - if (offset != null && offset >= objectSize) { - throwException(objectSize, offset, "offset"); - } - - if (length != null) { - if (length > objectSize) { - throwException(objectSize, length, "length"); - } - - if (offset + length > objectSize) { - throwException(objectSize, offset + length, "compose size"); - } - } - } - - public void buildHeaders(long objectSize, String etag) { - validateSize(objectSize); - this.objectSize = Long.valueOf(objectSize); - Multimap headers = genCopyHeaders(); - if (!headers.containsKey("x-amz-copy-source-if-match")) { - headers.put("x-amz-copy-source-if-match", etag); - } - this.headers = Multimaps.unmodifiableMultimap(headers); - } - - public long objectSize() throws InternalException { - if (this.objectSize == null) { - throw new InternalException( - "buildHeaders(long objectSize, String etag) must be called prior to this method invocation", - null); - } - - return this.objectSize; - } - - public Multimap headers() throws InternalException { - if (this.headers == null) { - throw new InternalException( - "buildHeaders(long objectSize, String etag) must be called prior to this method invocation", - null); - } - - return this.headers; - } - - public static Builder builder() { - return new Builder(); - } - - /** Argument builder of {@link ComposeSource}. */ - public static final class Builder - extends ObjectConditionalReadArgs.Builder {} - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ComposeSource)) return false; - if (!super.equals(o)) return false; - ComposeSource that = (ComposeSource) o; - return Objects.equals(objectSize, that.objectSize) && Objects.equals(headers, that.headers); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), objectSize, headers); - } -} diff --git a/api/src/main/java/io/minio/CopyObjectArgs.java b/api/src/main/java/io/minio/CopyObjectArgs.java index 2108ab531..d113ae80c 100644 --- a/api/src/main/java/io/minio/CopyObjectArgs.java +++ b/api/src/main/java/io/minio/CopyObjectArgs.java @@ -17,32 +17,31 @@ package io.minio; import java.util.Objects; -import okhttp3.HttpUrl; -/** Argument class of {@link MinioAsyncClient#copyObject} and {@link MinioClient#copyObject}. */ +/** + * Arguments of {@link BaseS3Client#copyObject}, {@link MinioAsyncClient#copyObject} and {@link + * MinioClient#copyObject}. + */ public class CopyObjectArgs extends ObjectWriteArgs { - private CopySource source = null; + private SourceObject source; private Directive metadataDirective; private Directive taggingDirective; protected CopyObjectArgs() {} + public CopyObjectArgs(CopyObjectArgs args, SourceObject source) { + super(args); + this.metadataDirective = args.metadataDirective; + this.taggingDirective = args.taggingDirective; + this.source = source; + } + public CopyObjectArgs(ComposeObjectArgs args) { - this.extraHeaders = args.extraHeaders; - this.extraQueryParams = args.extraQueryParams; - this.bucketName = args.bucketName; - this.region = args.region; - this.objectName = args.objectName; - this.headers = args.headers; - this.userMetadata = args.userMetadata; - this.sse = args.sse; - this.tags = args.tags; - this.retention = args.retention; - this.legalHold = args.legalHold; - this.source = new CopySource(args.sources().get(0)); + super(args); + this.source = args.sources().get(0); } - public CopySource source() { + public SourceObject source() { return source; } @@ -59,31 +58,31 @@ public static Builder builder() { } @Override - public void validateSse(HttpUrl url) { - super.validateSse(url); - source.validateSsec(url); + public void validateSse(boolean isHttps) { + super.validateSse(isHttps); + source.validateSsec(isHttps); } - /** Argument builder of {@link CopyObjectArgs}. */ + /** Builder of {@link CopyObjectArgs}. */ public static final class Builder extends ObjectWriteArgs.Builder { @Override protected void validate(CopyObjectArgs args) { super.validate(args); - validateNotNull(args.source, "copy source"); + Utils.validateNotNull(args.source, "source object"); if (args.source.offset() != null || args.source.length() != null) { - if (args.metadataDirective != null && args.metadataDirective == Directive.COPY) { + if (args.metadataDirective == Directive.COPY) { throw new IllegalArgumentException( "COPY metadata directive is not applicable to source object with range"); } - if (args.taggingDirective != null && args.taggingDirective == Directive.COPY) { + if (args.taggingDirective == Directive.COPY) { throw new IllegalArgumentException( "COPY tagging directive is not applicable to source object with range"); } } } - public Builder source(CopySource source) { - validateNotNull(source, "copy source"); + public Builder source(SourceObject source) { + Utils.validateNotNull(source, "source object"); operations.add(args -> args.source = source); return this; } diff --git a/api/src/main/java/io/minio/CopySource.java b/api/src/main/java/io/minio/CopySource.java deleted file mode 100644 index bf3eca2cf..000000000 --- a/api/src/main/java/io/minio/CopySource.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio; - -/** A source object defintion for {@link CopyObjectArgs}. */ -public class CopySource extends ObjectConditionalReadArgs { - protected CopySource() {} - - public CopySource(ObjectConditionalReadArgs args) { - this.extraHeaders = args.extraHeaders; - this.extraQueryParams = args.extraQueryParams; - this.bucketName = args.bucketName; - this.region = args.region; - this.objectName = args.objectName; - this.versionId = args.versionId; - this.ssec = args.ssec; - this.offset = args.offset; - this.length = args.length; - this.matchETag = args.matchETag; - this.notMatchETag = args.notMatchETag; - this.modifiedSince = args.modifiedSince; - this.unmodifiedSince = args.unmodifiedSince; - } - - public static Builder builder() { - return new Builder(); - } - - /** Argument builder of {@link CopySource}. */ - public static final class Builder - extends ObjectConditionalReadArgs.Builder {} -} diff --git a/api/src/main/java/io/minio/messages/Version.java b/api/src/main/java/io/minio/CreateBucketArgs.java similarity index 57% rename from api/src/main/java/io/minio/messages/Version.java rename to api/src/main/java/io/minio/CreateBucketArgs.java index 65eb57d97..136cd5996 100644 --- a/api/src/main/java/io/minio/messages/Version.java +++ b/api/src/main/java/io/minio/CreateBucketArgs.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,21 @@ * limitations under the License. */ -package io.minio.messages; +package io.minio; -import org.simpleframework.xml.Root; +/** Arguments of {@link BaseS3Client#createBucket}. */ +public class CreateBucketArgs extends CreateBucketBaseArgs { + protected CreateBucketArgs() {} -/** Helper class to denote object and it's version information in {@link ListVersionsResult}. */ -@Root(name = "Version", strict = false) -public class Version extends Item { - public Version() { - super(); + public CreateBucketArgs(CreateBucketBaseArgs args) { + super(args); } - public Version(String prefix) { - super(prefix); + public static Builder builder() { + return new Builder(); } + + /** Builder of {@link CreateBucketArgs}. */ + public static final class Builder + extends CreateBucketBaseArgs.Builder {} } diff --git a/api/src/main/java/io/minio/CreateBucketBaseArgs.java b/api/src/main/java/io/minio/CreateBucketBaseArgs.java new file mode 100644 index 000000000..bf4f7cb08 --- /dev/null +++ b/api/src/main/java/io/minio/CreateBucketBaseArgs.java @@ -0,0 +1,89 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import io.minio.messages.CreateBucketConfiguration; +import java.util.Objects; + +/** Common arguments of {@link CreateBucketArgs} and {@link MakeBucketArgs}. */ +public abstract class CreateBucketBaseArgs extends BucketArgs { + protected boolean objectLock; + protected CreateBucketConfiguration.Location locationConfig; + protected CreateBucketConfiguration.Bucket bucket; + + protected CreateBucketBaseArgs() {} + + protected CreateBucketBaseArgs(CreateBucketBaseArgs args) { + super(args); + this.objectLock = args.objectLock; + this.locationConfig = args.locationConfig; + this.bucket = args.bucket; + } + + public boolean objectLock() { + return objectLock; + } + + public CreateBucketConfiguration.Location locationConfig() { + return locationConfig; + } + + public CreateBucketConfiguration.Bucket bucketConfig() { + return bucket; + } + + /** Base argument builder of {@link CreateBucketBaseArgs}. */ + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public abstract static class Builder, A extends CreateBucketBaseArgs> + extends BucketArgs.Builder { + public B objectLock(boolean objectLock) { + operations.add(args -> args.objectLock = objectLock); + return (B) this; + } + + public B locationConstraint(String region) { + operations.add(args -> args.region = region); + return (B) this; + } + + public B locationConfig(CreateBucketConfiguration.Location locationConfig) { + operations.add(args -> args.locationConfig = locationConfig); + return (B) this; + } + + public B bucketConfig(CreateBucketConfiguration.Bucket bucket) { + operations.add(args -> args.bucket = bucket); + return (B) this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CreateBucketBaseArgs)) return false; + if (!super.equals(o)) return false; + CreateBucketBaseArgs that = (CreateBucketBaseArgs) o; + return objectLock == that.objectLock + && Objects.equals(locationConfig, that.locationConfig) + && Objects.equals(bucket, that.bucket); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), objectLock, locationConfig, bucket); + } +} diff --git a/api/src/main/java/io/minio/CreateMultipartUploadArgs.java b/api/src/main/java/io/minio/CreateMultipartUploadArgs.java new file mode 100644 index 000000000..4c07885ec --- /dev/null +++ b/api/src/main/java/io/minio/CreateMultipartUploadArgs.java @@ -0,0 +1,78 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; +import okhttp3.MediaType; + +/** Arguments of {@link BaseS3Client#createMultipartUpload}. */ +public class CreateMultipartUploadArgs extends ObjectArgs { + private Http.Headers headers; + + protected CreateMultipartUploadArgs() {} + + public CreateMultipartUploadArgs( + PutObjectBaseArgs args, MediaType contentType, Checksum.Algorithm algorithm) { + super(args); + this.headers = + args.makeHeaders( + contentType, + algorithm == null + ? null + : new Http.Headers("x-amz-checksum-algorithm", algorithm.toString())); + } + + public CreateMultipartUploadArgs(ComposeObjectArgs args) { + super(args); + this.headers = args.makeHeaders(); + } + + public Http.Headers headers() { + return headers; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link CreateMultipartUploadArgs}. */ + public static final class Builder extends ObjectArgs.Builder { + @Override + protected void validate(CreateMultipartUploadArgs args) { + super.validate(args); + } + + public Builder headers(Http.Headers headers) { + operations.add(args -> args.headers = headers); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CreateMultipartUploadArgs)) return false; + if (!super.equals(o)) return false; + CreateMultipartUploadArgs that = (CreateMultipartUploadArgs) o; + return Objects.equals(headers, that.headers); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), headers); + } +} diff --git a/api/src/main/java/io/minio/CreateMultipartUploadResponse.java b/api/src/main/java/io/minio/CreateMultipartUploadResponse.java index 977f1b6d4..117d0e701 100644 --- a/api/src/main/java/io/minio/CreateMultipartUploadResponse.java +++ b/api/src/main/java/io/minio/CreateMultipartUploadResponse.java @@ -19,7 +19,7 @@ import io.minio.messages.InitiateMultipartUploadResult; import okhttp3.Headers; -/** Response class of {@link S3Base#createMultipartUploadAsync}. */ +/** Response of {@link BaseS3Client#createMultipartUpload}. */ public class CreateMultipartUploadResponse extends GenericResponse { private InitiateMultipartUploadResult result; diff --git a/api/src/main/java/io/minio/DeleteBucketCorsArgs.java b/api/src/main/java/io/minio/DeleteBucketCorsArgs.java index b56679da8..fda545888 100644 --- a/api/src/main/java/io/minio/DeleteBucketCorsArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketCorsArgs.java @@ -17,14 +17,13 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketCors} and {@link - * MinioClient#deleteBucketCors}. + * Arguments of {@link MinioAsyncClient#deleteBucketCors} and {@link MinioClient#deleteBucketCors}. */ public class DeleteBucketCorsArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketCorsArgs}. */ + /** Builder of {@link DeleteBucketCorsArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteBucketEncryptionArgs.java b/api/src/main/java/io/minio/DeleteBucketEncryptionArgs.java index 2109e2a75..fb31b1af9 100644 --- a/api/src/main/java/io/minio/DeleteBucketEncryptionArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketEncryptionArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketEncryption} and {@link + * Arguments of {@link MinioAsyncClient#deleteBucketEncryption} and {@link * MinioClient#deleteBucketEncryption}. */ public class DeleteBucketEncryptionArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketEncryptionArgs}. */ + /** Builder of {@link DeleteBucketEncryptionArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteBucketLifecycleArgs.java b/api/src/main/java/io/minio/DeleteBucketLifecycleArgs.java index 3c790a8b6..141a0869d 100644 --- a/api/src/main/java/io/minio/DeleteBucketLifecycleArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketLifecycleArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketLifecycle} and {@link + * Arguments of {@link MinioAsyncClient#deleteBucketLifecycle} and {@link * MinioClient#deleteBucketLifecycle}. */ public class DeleteBucketLifecycleArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketLifecycleArgs}. */ + /** Builder of {@link DeleteBucketLifecycleArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteBucketNotificationArgs.java b/api/src/main/java/io/minio/DeleteBucketNotificationArgs.java index 72a593d0a..e3f649f70 100644 --- a/api/src/main/java/io/minio/DeleteBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketNotificationArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketNotification} and {@link + * Arguments of {@link MinioAsyncClient#deleteBucketNotification} and {@link * MinioClient#deleteBucketNotification}. */ public class DeleteBucketNotificationArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketNotificationArgs}. */ + /** Builder of {@link DeleteBucketNotificationArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteBucketPolicyArgs.java b/api/src/main/java/io/minio/DeleteBucketPolicyArgs.java index 466811907..be189d51a 100644 --- a/api/src/main/java/io/minio/DeleteBucketPolicyArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketPolicyArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketPolicy} and {@link + * Arguments of {@link MinioAsyncClient#deleteBucketPolicy} and {@link * MinioClient#deleteBucketPolicy}. */ public class DeleteBucketPolicyArgs extends BucketArgs { @@ -25,6 +25,6 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketPolicyArgs}. */ + /** Builder of {@link DeleteBucketPolicyArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteBucketReplicationArgs.java b/api/src/main/java/io/minio/DeleteBucketReplicationArgs.java index 1e0842dc2..ad489082d 100644 --- a/api/src/main/java/io/minio/DeleteBucketReplicationArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketReplicationArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketReplication} and {@link + * Arguments of {@link MinioAsyncClient#deleteBucketReplication} and {@link * MinioClient#deleteBucketReplication}. */ public class DeleteBucketReplicationArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketReplicationArgs}. */ + /** Builder of {@link DeleteBucketReplicationArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteBucketTagsArgs.java b/api/src/main/java/io/minio/DeleteBucketTagsArgs.java index 0bff8b08c..91cbab136 100644 --- a/api/src/main/java/io/minio/DeleteBucketTagsArgs.java +++ b/api/src/main/java/io/minio/DeleteBucketTagsArgs.java @@ -17,14 +17,13 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteBucketTags} and {@link - * MinioClient#deleteBucketTags}. + * Arguments of {@link MinioAsyncClient#deleteBucketTags} and {@link MinioClient#deleteBucketTags}. */ public class DeleteBucketTagsArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteBucketTagsArgs}. */ + /** Builder of {@link DeleteBucketTagsArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteObjectLockConfigurationArgs.java b/api/src/main/java/io/minio/DeleteObjectLockConfigurationArgs.java index df12f8d65..bafebd5fc 100644 --- a/api/src/main/java/io/minio/DeleteObjectLockConfigurationArgs.java +++ b/api/src/main/java/io/minio/DeleteObjectLockConfigurationArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteObjectLockConfiguration} and {@link + * Arguments of {@link MinioAsyncClient#deleteObjectLockConfiguration} and {@link * MinioClient#deleteObjectLockConfiguration}. */ public class DeleteObjectLockConfigurationArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteObjectLockConfigurationArgs}. */ + /** Builder of {@link DeleteObjectLockConfigurationArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteObjectTagsArgs.java b/api/src/main/java/io/minio/DeleteObjectTagsArgs.java index daf65b613..13d9c5367 100644 --- a/api/src/main/java/io/minio/DeleteObjectTagsArgs.java +++ b/api/src/main/java/io/minio/DeleteObjectTagsArgs.java @@ -17,15 +17,14 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#deleteObjectTags} and {@link - * MinioClient#deleteObjectTags}. + * Arguments of {@link MinioAsyncClient#deleteObjectTags} and {@link MinioClient#deleteObjectTags}. */ public class DeleteObjectTagsArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DeleteObjectTagsArgs}. */ + /** Builder of {@link DeleteObjectTagsArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DeleteObjectsArgs.java b/api/src/main/java/io/minio/DeleteObjectsArgs.java new file mode 100644 index 000000000..40eb7237a --- /dev/null +++ b/api/src/main/java/io/minio/DeleteObjectsArgs.java @@ -0,0 +1,92 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import io.minio.messages.DeleteRequest; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#deleteObjects}. */ +public class DeleteObjectsArgs extends BucketArgs { + private boolean quiet; + private boolean bypassGovernanceMode; + private List objects = new LinkedList<>(); + + public boolean quiet() { + return quiet; + } + + public boolean bypassGovernanceMode() { + return bypassGovernanceMode; + } + + public List objects() { + return objects; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link DeleteObjectsArgs}. */ + public static final class Builder extends BucketArgs.Builder { + @Override + protected void validate(DeleteObjectsArgs args) { + super.validate(args); + Utils.validateNotNull(args.objects, "objects"); + if (args.objects.size() > 1000) { + throw new IllegalArgumentException("list of objects must not be more than 1000"); + } + } + + public Builder quiet(boolean flag) { + operations.add(args -> args.quiet = flag); + return this; + } + + public Builder bypassGovernanceMode(boolean flag) { + operations.add(args -> args.bypassGovernanceMode = flag); + return this; + } + + public Builder objects(List objects) { + Utils.validateNotNull(objects, "objects"); + if (objects.size() > 1000) { + throw new IllegalArgumentException("list of objects must not be more than 1000"); + } + operations.add(args -> args.objects = objects); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DeleteObjectsArgs)) return false; + if (!super.equals(o)) return false; + DeleteObjectsArgs that = (DeleteObjectsArgs) o; + return quiet == that.quiet + && bypassGovernanceMode == that.bypassGovernanceMode + && Objects.equals(objects, that.objects); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), quiet, bypassGovernanceMode, objects); + } +} diff --git a/api/src/main/java/io/minio/DeleteObjectsResponse.java b/api/src/main/java/io/minio/DeleteObjectsResponse.java index 745e27068..7a1ade135 100644 --- a/api/src/main/java/io/minio/DeleteObjectsResponse.java +++ b/api/src/main/java/io/minio/DeleteObjectsResponse.java @@ -19,7 +19,7 @@ import io.minio.messages.DeleteResult; import okhttp3.Headers; -/** Response class of {@link S3Base#deleteObjectsAsync}. */ +/** Response of {@link MinioAsyncClient#deleteObjects}. */ public class DeleteObjectsResponse extends GenericResponse { private DeleteResult result; diff --git a/api/src/main/java/io/minio/Digest.java b/api/src/main/java/io/minio/Digest.java deleted file mode 100644 index 22d13134c..000000000 --- a/api/src/main/java/io/minio/Digest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio; - -import com.google.common.io.BaseEncoding; -import io.minio.errors.InsufficientDataException; -import io.minio.errors.InternalException; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; -import java.util.Locale; - -/** Various global static functions used. */ -public class Digest { - // MD5 hash of zero length byte array. - public static final String ZERO_MD5_HASH = "1B2M2Y8AsgTpgAmY7PhCfg=="; - // SHA-256 hash of zero length byte array. - public static final String ZERO_SHA256_HASH = - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; - - /** Private constructor. */ - private Digest() {} - - /** Returns MD5 hash of byte array. */ - public static String md5Hash(byte[] data, int length) throws NoSuchAlgorithmException { - MessageDigest md5Digest = MessageDigest.getInstance("MD5"); - md5Digest.update(data, 0, length); - return Base64.getEncoder().encodeToString(md5Digest.digest()); - } - - /** Returns SHA-256 hash of byte array. */ - public static String sha256Hash(byte[] data, int length) throws NoSuchAlgorithmException { - MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256"); - sha256Digest.update((byte[]) data, 0, length); - return BaseEncoding.base16().encode(sha256Digest.digest()).toLowerCase(Locale.US); - } - - /** Returns SHA-256 hash of given string. */ - public static String sha256Hash(String string) throws NoSuchAlgorithmException { - byte[] data = string.getBytes(StandardCharsets.UTF_8); - return sha256Hash(data, data.length); - } - - /** - * Returns SHA-256 and MD5 hashes of given data and it's length. - * - * @param data must be {@link RandomAccessFile}, {@link BufferedInputStream} or byte array. - * @param len length of data to be read for hash calculation. - * @deprecated This method is no longer supported. - */ - @Deprecated - public static String[] sha256Md5Hashes(Object data, int len) - throws NoSuchAlgorithmException, IOException, InsufficientDataException, InternalException { - MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256"); - MessageDigest md5Digest = MessageDigest.getInstance("MD5"); - - if (data instanceof BufferedInputStream || data instanceof RandomAccessFile) { - updateDigests(data, len, sha256Digest, md5Digest); - } else if (data instanceof byte[]) { - sha256Digest.update((byte[]) data, 0, len); - md5Digest.update((byte[]) data, 0, len); - } else { - throw new InternalException( - "Unknown data source to calculate SHA-256 hash. This should not happen, " - + "please report this issue at https://github.com/minio/minio-java/issues", - null); - } - - return new String[] { - BaseEncoding.base16().encode(sha256Digest.digest()).toLowerCase(Locale.US), - BaseEncoding.base64().encode(md5Digest.digest()) - }; - } - - /** Updated MessageDigest with bytes read from file and stream. */ - private static int updateDigests( - Object inputStream, int len, MessageDigest sha256Digest, MessageDigest md5Digest) - throws IOException, InsufficientDataException { - RandomAccessFile file = null; - BufferedInputStream stream = null; - if (inputStream instanceof RandomAccessFile) { - file = (RandomAccessFile) inputStream; - } else if (inputStream instanceof BufferedInputStream) { - stream = (BufferedInputStream) inputStream; - } - - // hold current position of file/stream to reset back to this position. - long pos = 0; - if (file != null) { - pos = file.getFilePointer(); - } else { - stream.mark(len); - } - - // 16KiB buffer for optimization - byte[] buf = new byte[16384]; - int bytesToRead = buf.length; - int bytesRead = 0; - int totalBytesRead = 0; - while (totalBytesRead < len) { - if ((len - totalBytesRead) < bytesToRead) { - bytesToRead = len - totalBytesRead; - } - - if (file != null) { - bytesRead = file.read(buf, 0, bytesToRead); - } else { - bytesRead = stream.read(buf, 0, bytesToRead); - } - - if (bytesRead < 0) { - // reached EOF - throw new InsufficientDataException( - "Insufficient data. bytes read " + totalBytesRead + " expected " + len); - } - - if (bytesRead > 0) { - if (sha256Digest != null) { - sha256Digest.update(buf, 0, bytesRead); - } - - if (md5Digest != null) { - md5Digest.update(buf, 0, bytesRead); - } - - totalBytesRead += bytesRead; - } - } - - // reset back to saved position. - if (file != null) { - file.seek(pos); - } else { - stream.reset(); - } - - return totalBytesRead; - } -} diff --git a/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java b/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java index 9cae46502..6d3aae02d 100644 --- a/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java +++ b/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#disableObjectLegalHold} and {@link + * Arguments of {@link MinioAsyncClient#disableObjectLegalHold} and {@link * MinioClient#disableObjectLegalHold}. */ public class DisableObjectLegalHoldArgs extends ObjectVersionArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link DisableObjectLegalHoldArgs}. */ + /** Builder of {@link DisableObjectLegalHoldArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DownloadObjectArgs.java b/api/src/main/java/io/minio/DownloadObjectArgs.java index eb9fa6daf..fbbe257c4 100644 --- a/api/src/main/java/io/minio/DownloadObjectArgs.java +++ b/api/src/main/java/io/minio/DownloadObjectArgs.java @@ -18,9 +18,7 @@ import java.util.Objects; -/** - * Argument class of {@link MinioAsyncClient#downloadObject} and {@link MinioClient#downloadObject}. - */ +/** Arguments of {@link MinioAsyncClient#downloadObject} and {@link MinioClient#downloadObject}. */ public class DownloadObjectArgs extends ObjectReadArgs { private String filename; private boolean overwrite; @@ -37,10 +35,10 @@ public static Builder builder() { return new Builder(); } - /** Argument class of {@link DownloadObjectArgs}. */ + /** Arguments of {@link DownloadObjectArgs}. */ public static final class Builder extends ObjectReadArgs.Builder { private void validateFilename(String filename) { - validateNotEmptyString(filename, "filename"); + Utils.validateNotEmptyString(filename, "filename"); } public Builder filename(String filename) { diff --git a/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java b/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java index 58807f45b..afeb50ef6 100644 --- a/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java +++ b/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#enableObjectLegalHold} and {@link + * Arguments of {@link MinioAsyncClient#enableObjectLegalHold} and {@link * MinioClient#enableObjectLegalHold}. */ public class EnableObjectLegalHoldArgs extends ObjectVersionArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link EnableObjectLegalHoldArgs}. */ + /** Builder of {@link EnableObjectLegalHoldArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GenericResponse.java b/api/src/main/java/io/minio/GenericResponse.java index ac330f656..16585c6fc 100644 --- a/api/src/main/java/io/minio/GenericResponse.java +++ b/api/src/main/java/io/minio/GenericResponse.java @@ -18,7 +18,7 @@ import okhttp3.Headers; -/** Generic response class of any APIs. */ +/** Generic response of any APIs. */ public class GenericResponse { private Headers headers; private String bucket; diff --git a/api/src/main/java/io/minio/GenericUploadResponse.java b/api/src/main/java/io/minio/GenericUploadResponse.java index c8b012138..774de2ba9 100644 --- a/api/src/main/java/io/minio/GenericUploadResponse.java +++ b/api/src/main/java/io/minio/GenericUploadResponse.java @@ -20,7 +20,7 @@ import io.minio.messages.CopyObjectResult; import okhttp3.Headers; -/** Response class of any APIs doing object/part upload. */ +/** Commonm response of {@link ObjectWriteResponse} and {@link PutObjectFanOutResponse}. */ public class GenericUploadResponse extends GenericResponse { private String etag; private String checksumCRC32; diff --git a/api/src/main/java/io/minio/GetBucketCorsArgs.java b/api/src/main/java/io/minio/GetBucketCorsArgs.java index 477310038..df9043342 100644 --- a/api/src/main/java/io/minio/GetBucketCorsArgs.java +++ b/api/src/main/java/io/minio/GetBucketCorsArgs.java @@ -16,14 +16,12 @@ package io.minio; -/** - * Argument class of {@link MinioAsyncClient#getBucketCors} and {@link MinioClient#getBucketCors}. - */ +/** Arguments of {@link MinioAsyncClient#getBucketCors} and {@link MinioClient#getBucketCors}. */ public class GetBucketCorsArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketCorsArgs}. */ + /** Builder of {@link GetBucketCorsArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketEncryptionArgs.java b/api/src/main/java/io/minio/GetBucketEncryptionArgs.java index fe21b565f..c7e0d6ab6 100644 --- a/api/src/main/java/io/minio/GetBucketEncryptionArgs.java +++ b/api/src/main/java/io/minio/GetBucketEncryptionArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getBucketEncryption} and {@link + * Arguments of {@link MinioAsyncClient#getBucketEncryption} and {@link * MinioClient#getBucketEncryption}. */ public class GetBucketEncryptionArgs extends BucketArgs { @@ -25,6 +25,6 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketEncryptionArgs}. */ + /** Builder of {@link GetBucketEncryptionArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketLifecycleArgs.java b/api/src/main/java/io/minio/GetBucketLifecycleArgs.java index d4c7585c4..0fc457d47 100644 --- a/api/src/main/java/io/minio/GetBucketLifecycleArgs.java +++ b/api/src/main/java/io/minio/GetBucketLifecycleArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getBucketLifecycle} and {@link + * Arguments of {@link MinioAsyncClient#getBucketLifecycle} and {@link * MinioClient#getBucketLifecycle}. */ public class GetBucketLifecycleArgs extends BucketArgs { @@ -25,6 +25,6 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketLifecycleArgs}. */ + /** Builder of {@link GetBucketLifecycleArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/messages/DeleteMarker.java b/api/src/main/java/io/minio/GetBucketLocationArgs.java similarity index 63% rename from api/src/main/java/io/minio/messages/DeleteMarker.java rename to api/src/main/java/io/minio/GetBucketLocationArgs.java index 0e95b74ed..4a61a0795 100644 --- a/api/src/main/java/io/minio/messages/DeleteMarker.java +++ b/api/src/main/java/io/minio/GetBucketLocationArgs.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,14 @@ * limitations under the License. */ -package io.minio.messages; +package io.minio; -import org.simpleframework.xml.Root; - -/** Helper class to denote delete marker information in {@link ListVersionsResult}. */ -@Root(name = "DeleteMarker", strict = false) -public class DeleteMarker extends Item { - public DeleteMarker() { - super(); +/** Arguments of {@link BaseS3Client#getBucketLocation}. */ +public class GetBucketLocationArgs extends BucketArgs { + public static Builder builder() { + return new Builder(); } - public DeleteMarker(String prefix) { - super(prefix); - } + /** Builder of {@link GetBucketLocationArgs}. */ + public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketNotificationArgs.java b/api/src/main/java/io/minio/GetBucketNotificationArgs.java index 48502dabb..4471d8ba0 100644 --- a/api/src/main/java/io/minio/GetBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/GetBucketNotificationArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getBucketNotification} and {@link + * Arguments of {@link MinioAsyncClient#getBucketNotification} and {@link * MinioClient#getBucketNotification}. */ public class GetBucketNotificationArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketNotificationArgs}. */ + /** Builder of {@link GetBucketNotificationArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketPolicyArgs.java b/api/src/main/java/io/minio/GetBucketPolicyArgs.java index a896ee8fe..294ac04c2 100644 --- a/api/src/main/java/io/minio/GetBucketPolicyArgs.java +++ b/api/src/main/java/io/minio/GetBucketPolicyArgs.java @@ -17,14 +17,13 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getBucketPolicy} and {@link - * MinioClient#getBucketPolicy}. + * Arguments of {@link MinioAsyncClient#getBucketPolicy} and {@link MinioClient#getBucketPolicy}. */ public class GetBucketPolicyArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketPolicyArgs}. */ + /** Builder of {@link GetBucketPolicyArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketReplicationArgs.java b/api/src/main/java/io/minio/GetBucketReplicationArgs.java index 6e1dc4335..9fd5ff179 100644 --- a/api/src/main/java/io/minio/GetBucketReplicationArgs.java +++ b/api/src/main/java/io/minio/GetBucketReplicationArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getBucketReplication} and {@link + * Arguments of {@link MinioAsyncClient#getBucketReplication} and {@link * MinioClient#getBucketReplication}. */ public class GetBucketReplicationArgs extends BucketArgs { @@ -25,6 +25,6 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketReplicationArgs}. */ + /** Builder of {@link GetBucketReplicationArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketTagsArgs.java b/api/src/main/java/io/minio/GetBucketTagsArgs.java index 8e4c104d3..fa891330e 100644 --- a/api/src/main/java/io/minio/GetBucketTagsArgs.java +++ b/api/src/main/java/io/minio/GetBucketTagsArgs.java @@ -16,14 +16,12 @@ package io.minio; -/** - * Argument class of {@link MinioAsyncClient#getBucketTags} and {@link MinioClient#getBucketTags}. - */ +/** Arguments of {@link MinioAsyncClient#getBucketTags} and {@link MinioClient#getBucketTags}. */ public class GetBucketTagsArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketTagsArgs}. */ + /** Builder of {@link GetBucketTagsArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetBucketVersioningArgs.java b/api/src/main/java/io/minio/GetBucketVersioningArgs.java index 72c436fdb..1a67d805d 100644 --- a/api/src/main/java/io/minio/GetBucketVersioningArgs.java +++ b/api/src/main/java/io/minio/GetBucketVersioningArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getBucketVersioning} and {@link + * Arguments of {@link MinioAsyncClient#getBucketVersioning} and {@link * MinioClient#getBucketVersioning}. */ public class GetBucketVersioningArgs extends BucketArgs { @@ -25,6 +25,6 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetBucketVersioningArgs}. */ + /** Builder of {@link GetBucketVersioningArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectAclArgs.java b/api/src/main/java/io/minio/GetObjectAclArgs.java index 840b25fc0..c0e56568a 100644 --- a/api/src/main/java/io/minio/GetObjectAclArgs.java +++ b/api/src/main/java/io/minio/GetObjectAclArgs.java @@ -16,12 +16,12 @@ package io.minio; -/** Argument class of {@link MinioAsyncClient#getObjectAcl} and {@link MinioClient#getObjectAcl}. */ +/** Arguments of {@link MinioAsyncClient#getObjectAcl} and {@link MinioClient#getObjectAcl}. */ public class GetObjectAclArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetObjectAclArgs}. */ + /** Builder of {@link GetObjectAclArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectArgs.java b/api/src/main/java/io/minio/GetObjectArgs.java index 709d2c255..eecf41ca5 100644 --- a/api/src/main/java/io/minio/GetObjectArgs.java +++ b/api/src/main/java/io/minio/GetObjectArgs.java @@ -16,7 +16,7 @@ package io.minio; -/** Argument class of {@link MinioAsyncClient#getObject} and {@link MinioClient#getObject}. */ +/** Arguments of {@link MinioAsyncClient#getObject} and {@link MinioClient#getObject}. */ public class GetObjectArgs extends ObjectConditionalReadArgs { protected GetObjectArgs() {} @@ -34,7 +34,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetObjectArgs}. */ + /** Builder of {@link GetObjectArgs}. */ public static final class Builder extends ObjectConditionalReadArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectAttributesArgs.java b/api/src/main/java/io/minio/GetObjectAttributesArgs.java index 19bd9bbba..b414bc64a 100644 --- a/api/src/main/java/io/minio/GetObjectAttributesArgs.java +++ b/api/src/main/java/io/minio/GetObjectAttributesArgs.java @@ -21,7 +21,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#getObjectAttributes} and {@link + * Arguments of {@link MinioAsyncClient#getObjectAttributes} and {@link * MinioClient#getObjectAttributes}. */ public class GetObjectAttributesArgs extends ObjectReadArgs { @@ -45,13 +45,13 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetObjectAttributesArgs}. */ + /** Builder of {@link GetObjectAttributesArgs}. */ public static final class Builder extends ObjectReadArgs.Builder { @Override protected void validate(GetObjectAttributesArgs args) { super.validate(args); - validateNotNull(args.objectAttributes, "object attributes"); + Utils.validateNotNull(args.objectAttributes, "object attributes"); } public Builder objectAttributes(String[] objectAttributes) { diff --git a/api/src/main/java/io/minio/GetObjectAttributesResponse.java b/api/src/main/java/io/minio/GetObjectAttributesResponse.java index bbb4e95e6..ce98157d4 100644 --- a/api/src/main/java/io/minio/GetObjectAttributesResponse.java +++ b/api/src/main/java/io/minio/GetObjectAttributesResponse.java @@ -20,7 +20,7 @@ import okhttp3.Headers; /** - * Response class of {@link MinioAsyncClient#getObjectAttributes} and {@link + * Response of {@link MinioAsyncClient#getObjectAttributes} and {@link * MinioClient#getObjectAttributes}. */ public class GetObjectAttributesResponse extends GenericResponse { diff --git a/api/src/main/java/io/minio/GetObjectLockConfigurationArgs.java b/api/src/main/java/io/minio/GetObjectLockConfigurationArgs.java index 481c219a1..626a5eb64 100644 --- a/api/src/main/java/io/minio/GetObjectLockConfigurationArgs.java +++ b/api/src/main/java/io/minio/GetObjectLockConfigurationArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getObjectLockConfiguration} and {@link + * Arguments of {@link MinioAsyncClient#getObjectLockConfiguration} and {@link * MinioClient#getObjectLockConfiguration}. */ public class GetObjectLockConfigurationArgs extends BucketArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetObjectLockConfigurationArgs}. */ + /** Builder of {@link GetObjectLockConfigurationArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectResponse.java b/api/src/main/java/io/minio/GetObjectResponse.java index 23f6fc385..4d4b60033 100644 --- a/api/src/main/java/io/minio/GetObjectResponse.java +++ b/api/src/main/java/io/minio/GetObjectResponse.java @@ -21,9 +21,9 @@ import okhttp3.Headers; /** - * Response class of {@link MinioAsyncClient#getObject} and {@link MinioClient#getObject}. This - * class is {@link InputStream} interface compatible and it must be closed after use to release - * underneath network resources. + * Response of {@link MinioAsyncClient#getObject} and {@link MinioClient#getObject}. As it is {@link + * InputStream} interface compatible, it must be closed after use to release underneath network + * resources. */ public class GetObjectResponse extends FilterInputStream { private GenericResponse response; diff --git a/api/src/main/java/io/minio/GetObjectRetentionArgs.java b/api/src/main/java/io/minio/GetObjectRetentionArgs.java index 2bdd12af5..aef88774d 100644 --- a/api/src/main/java/io/minio/GetObjectRetentionArgs.java +++ b/api/src/main/java/io/minio/GetObjectRetentionArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#getObjectRetention} and {@link + * Arguments of {@link MinioAsyncClient#getObjectRetention} and {@link * MinioClient#getObjectRetention}. */ public class GetObjectRetentionArgs extends ObjectVersionArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetObjectRetentionArgs}. */ + /** Builder of {@link GetObjectRetentionArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectTagsArgs.java b/api/src/main/java/io/minio/GetObjectTagsArgs.java index f71ec408d..4356d47f4 100644 --- a/api/src/main/java/io/minio/GetObjectTagsArgs.java +++ b/api/src/main/java/io/minio/GetObjectTagsArgs.java @@ -16,14 +16,12 @@ package io.minio; -/** - * Argument class of {@link MinioAsyncClient#getObjectTags} and {@link MinioClient#getObjectTags}. - */ +/** Arguments of {@link MinioAsyncClient#getObjectTags} and {@link MinioClient#getObjectTags}. */ public class GetObjectTagsArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetObjectTagsArgs}. */ + /** Builder of {@link GetObjectTagsArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java b/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java index a6e3d2a23..ea221ea37 100644 --- a/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java +++ b/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java @@ -16,22 +16,21 @@ package io.minio; -import io.minio.http.Method; import java.util.Objects; import java.util.concurrent.TimeUnit; /** - * Argument class of {@link MinioAsyncClient#getPresignedObjectUrl} and {@link + * Arguments of {@link MinioAsyncClient#getPresignedObjectUrl} and {@link * MinioClient#getPresignedObjectUrl}. */ public class GetPresignedObjectUrlArgs extends ObjectVersionArgs { // default expiration for a presigned URL is 7 days in seconds public static final int DEFAULT_EXPIRY_TIME = (int) TimeUnit.DAYS.toSeconds(7); - private Method method; + private Http.Method method; private int expiry = DEFAULT_EXPIRY_TIME; - public Method method() { + public Http.Method method() { return method; } @@ -43,11 +42,11 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link GetPresignedObjectUrlArgs}. */ + /** Builder of {@link GetPresignedObjectUrlArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder { - private void validateMethod(Method method) { - validateNotNull(method, "method"); + private void validateMethod(Http.Method method) { + Utils.validateNotNull(method, "method"); } private void validateExpiry(int expiry) { @@ -60,7 +59,7 @@ private void validateExpiry(int expiry) { } /* method HTTP {@link Method} to generate presigned URL. */ - public Builder method(Method method) { + public Builder method(Http.Method method) { validateMethod(method); operations.add(args -> args.method = method); return this; diff --git a/api/src/main/java/io/minio/ServerSideEncryptionS3.java b/api/src/main/java/io/minio/HeadObjectArgs.java similarity index 53% rename from api/src/main/java/io/minio/ServerSideEncryptionS3.java rename to api/src/main/java/io/minio/HeadObjectArgs.java index 4a2615ee7..64bba5a97 100644 --- a/api/src/main/java/io/minio/ServerSideEncryptionS3.java +++ b/api/src/main/java/io/minio/HeadObjectArgs.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,31 +16,26 @@ package io.minio; -import java.util.HashMap; -import java.util.Map; +/** Arguments of {@link BaseS3Client#headObject}. */ +public class HeadObjectArgs extends HeadObjectBaseArgs { + protected HeadObjectArgs() {} -/** S3 type of Server-side encryption. */ -public class ServerSideEncryptionS3 extends ServerSideEncryption { - private static final Map headers; - - static { - Map map = new HashMap<>(); - map.put("X-Amz-Server-Side-Encryption", "AES256"); - headers = Utils.unmodifiableMap(map); + public HeadObjectArgs(SourceObject args) { + super(args); } - @Override - public final Map headers() { - return headers; + public HeadObjectArgs(DownloadObjectArgs args) { + super(args); } - @Override - public final boolean tlsRequired() { - return false; + public HeadObjectArgs(HeadObjectBaseArgs args) { + super(args); } - @Override - public String toString() { - return "SSE-S3"; + public static Builder builder() { + return new Builder(); } + + /** Builder of {@link HeadObjectArgs}. */ + public static final class Builder extends HeadObjectBaseArgs.Builder {} } diff --git a/api/src/main/java/io/minio/messages/QueueConfiguration.java b/api/src/main/java/io/minio/HeadObjectBaseArgs.java similarity index 50% rename from api/src/main/java/io/minio/messages/QueueConfiguration.java rename to api/src/main/java/io/minio/HeadObjectBaseArgs.java index 2123b6505..c71e88ba7 100644 --- a/api/src/main/java/io/minio/messages/QueueConfiguration.java +++ b/api/src/main/java/io/minio/HeadObjectBaseArgs.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,28 +14,25 @@ * limitations under the License. */ -package io.minio.messages; +package io.minio; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; +/** Common arguments of {@link HeadObjectArgs} and {@link StatObjectArgs}. */ +public abstract class HeadObjectBaseArgs extends ObjectConditionalReadArgs { + protected HeadObjectBaseArgs() {} -/** Helper class to denote Queue configuration of {@link NotificationConfiguration}. */ -@Root(name = "QueueConfiguration", strict = false) -public class QueueConfiguration extends NotificationCommonConfiguration { - @Element(name = "Queue") - private String queue; - - public QueueConfiguration() { - super(); + protected HeadObjectBaseArgs(SourceObject args) { + super(args); } - /** Returns queue. */ - public String queue() { - return queue; + protected HeadObjectBaseArgs(DownloadObjectArgs args) { + super(args); } - /** Sets queue. */ - public void setQueue(String queue) { - this.queue = queue; + protected HeadObjectBaseArgs(HeadObjectBaseArgs args) { + super(args); } + + /** Builder of {@link HeadObjectBaseArgs}. */ + public abstract static class Builder, A extends HeadObjectBaseArgs> + extends ObjectConditionalReadArgs.Builder {} } diff --git a/api/src/main/java/io/minio/HeadObjectResponse.java b/api/src/main/java/io/minio/HeadObjectResponse.java new file mode 100644 index 000000000..48c8eb891 --- /dev/null +++ b/api/src/main/java/io/minio/HeadObjectResponse.java @@ -0,0 +1,125 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import io.minio.messages.LegalHold; +import io.minio.messages.RetentionMode; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** Response of {@link BaseS3Client#headObject}. */ +public class HeadObjectResponse extends GenericResponse { + private String etag; + private long size; + private ZonedDateTime lastModified; + private RetentionMode retentionMode; + private ZonedDateTime retentionRetainUntilDate; + private LegalHold legalHold; + private boolean deleteMarker; + private Http.Headers userMetadata; + + public HeadObjectResponse(okhttp3.Headers headers, String bucket, String region, String object) { + super(headers, bucket, region, object); + String value; + + value = headers.get("ETag"); + this.etag = (value != null ? value.replaceAll("\"", "") : ""); + + value = headers.get(Http.Headers.CONTENT_LENGTH); + this.size = (value != null ? Long.parseLong(value) : -1); + + this.lastModified = + ZonedDateTime.parse(headers.get("Last-Modified"), Time.HTTP_HEADER_DATE_FORMAT); + + value = headers.get("x-amz-object-lock-mode"); + this.retentionMode = (value != null ? RetentionMode.valueOf(value) : null); + + value = headers.get("x-amz-object-lock-retain-until-date"); + this.retentionRetainUntilDate = + value == null ? null : Time.S3Time.fromString(value).toZonedDateTime(); + + this.legalHold = new LegalHold("ON".equals(headers.get("x-amz-object-lock-legal-hold"))); + + this.deleteMarker = Boolean.parseBoolean(headers.get("x-amz-delete-marker")); + + Http.Headers userMetadata = new Http.Headers(); + for (Map.Entry> entry : headers.toMultimap().entrySet()) { + String lowerName = entry.getKey().toLowerCase(Locale.US); + if (lowerName.startsWith("x-amz-meta-")) { + userMetadata.putAll( + lowerName.substring("x-amz-meta-".length(), lowerName.length()), entry.getValue()); + } + } + this.userMetadata = userMetadata; + } + + public String etag() { + return etag; + } + + public long size() { + return size; + } + + public ZonedDateTime lastModified() { + return lastModified; + } + + public RetentionMode retentionMode() { + return retentionMode; + } + + public ZonedDateTime retentionRetainUntilDate() { + return retentionRetainUntilDate; + } + + public LegalHold legalHold() { + return legalHold; + } + + public boolean deleteMarker() { + return deleteMarker; + } + + public String versionId() { + return this.headers().get("x-amz-version-id"); + } + + public String contentType() { + return this.headers().get(Http.Headers.CONTENT_TYPE); + } + + public Http.Headers userMetadata() { + return userMetadata; + } + + @Override + public String toString() { + return "ObjectHead{" + + "bucket=" + + bucket() + + ", object=" + + object() + + ", last-modified=" + + lastModified + + ", size=" + + size + + "}"; + } +} diff --git a/api/src/main/java/io/minio/Http.java b/api/src/main/java/io/minio/Http.java new file mode 100644 index 000000000..a61a93fca --- /dev/null +++ b/api/src/main/java/io/minio/Http.java @@ -0,0 +1,1458 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import io.minio.credentials.Credentials; +import io.minio.errors.MinioException; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.time.ZonedDateTime; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okio.BufferedSink; +import okio.Okio; + +/** HTTP utilities. */ +public class Http { + public static final MediaType DEFAULT_MEDIA_TYPE = MediaType.parse("application/octet-stream"); + public static final MediaType XML_MEDIA_TYPE = MediaType.parse("application/xml"); + public static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json"); + public static final String US_EAST_1 = "us-east-1"; + public static final long DEFAULT_TIMEOUT = TimeUnit.MINUTES.toMillis(5); + public static final byte[] ZERO_BODY = new byte[0]; + public static final Body EMPTY_BODY = + new Body(ZERO_BODY, 0, DEFAULT_MEDIA_TYPE, Checksum.ZERO_SHA256_HASH, Checksum.ZERO_MD5_HASH); + + /** Base URL of S3 endpoint. */ + public static class BaseUrl { + private okhttp3.HttpUrl url; + private String awsS3Prefix; + private String awsDomainSuffix; + private boolean awsDualstack; + private String region; + private boolean useVirtualStyle; + + public BaseUrl(String endpoint) { + setUrl(parse(endpoint)); + } + + public BaseUrl(String endpoint, int port, boolean secure) { + okhttp3.HttpUrl url = parse(endpoint); + if (port < 1 || port > 65535) { + throw new IllegalArgumentException("port must be in range of 1 to 65535"); + } + url = url.newBuilder().port(port).scheme(secure ? "https" : "http").build(); + + setUrl(url); + } + + public BaseUrl(okhttp3.HttpUrl url) { + Utils.validateNotNull(url, "url"); + Utils.validateUrl(url); + setUrl(url); + } + + public BaseUrl(URL url) { + Utils.validateNotNull(url, "url"); + setUrl(okhttp3.HttpUrl.get(url)); + } + + private void setAwsInfo(String host, boolean https) { + this.awsS3Prefix = null; + this.awsDomainSuffix = null; + this.awsDualstack = false; + + if (!Utils.HOSTNAME_REGEX.matcher(host).find()) return; + + if (Utils.AWS_ELB_ENDPOINT_REGEX.matcher(host).find()) { + String[] tokens = host.split("\\.elb\\.amazonaws\\.com", 1)[0].split("\\."); + this.region = tokens[tokens.length - 1]; + return; + } + + if (!Utils.AWS_ENDPOINT_REGEX.matcher(host).find()) return; + + if (!Utils.AWS_S3_ENDPOINT_REGEX.matcher(host).find()) { + throw new IllegalArgumentException("invalid Amazon AWS host " + host); + } + + Matcher matcher = Utils.AWS_S3_PREFIX_REGEX.matcher(host); + matcher.lookingAt(); + int end = matcher.end(); + + this.awsS3Prefix = host.substring(0, end); + if (this.awsS3Prefix.contains("s3-accesspoint") && !https) { + throw new IllegalArgumentException("use HTTPS scheme for host " + host); + } + + String[] tokens = host.substring(end).split("\\."); + awsDualstack = "dualstack".equals(tokens[0]); + if (awsDualstack) tokens = Arrays.copyOfRange(tokens, 1, tokens.length); + String regionInHost = null; + if (!tokens[0].equals("vpce") && !tokens[0].equals("amazonaws")) { + regionInHost = tokens[0]; + tokens = Arrays.copyOfRange(tokens, 1, tokens.length); + } + this.awsDomainSuffix = String.join(".", tokens); + + if (host.equals("s3-external-1.amazonaws.com")) regionInHost = "us-east-1"; + if (host.equals("s3-us-gov-west-1.amazonaws.com") + || host.equals("s3-fips-us-gov-west-1.amazonaws.com")) { + regionInHost = "us-gov-west-1"; + } + + if (regionInHost != null) this.region = regionInHost; + } + + private void setUrl(okhttp3.HttpUrl url) { + this.url = url; + this.setAwsInfo(url.host(), url.isHttps()); + this.useVirtualStyle = this.awsDomainSuffix != null || url.host().endsWith("aliyuncs.com"); + } + + private okhttp3.HttpUrl parse(String endpoint) { + Utils.validateNotEmptyString(endpoint, "endpoint"); + okhttp3.HttpUrl url = okhttp3.HttpUrl.parse(endpoint); + if (url == null) { + Utils.validateHostnameOrIPAddress(endpoint); + url = new okhttp3.HttpUrl.Builder().scheme("https").host(endpoint).build(); + } else { + Utils.validateUrl(url); + } + return url; + } + + public boolean isHttps() { + return url.isHttps(); + } + + public String awsS3Prefix() { + return awsS3Prefix; + } + + public String awsDomainSuffix() { + return awsDomainSuffix; + } + + public String region() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + /** Enables dual-stack endpoint for Amazon S3 endpoint. */ + public void enableDualStackEndpoint() { + awsDualstack = true; + } + + /** Disables dual-stack endpoint for Amazon S3 endpoint. */ + public void disableDualStackEndpoint() { + awsDualstack = false; + } + + /** Enables virtual-style endpoint. */ + public void enableVirtualStyleEndpoint() { + useVirtualStyle = true; + } + + /** Disables virtual-style endpoint. */ + public void disableVirtualStyleEndpoint() { + useVirtualStyle = false; + } + + /** Sets AWS S3 domain prefix. */ + public void setAwsS3Prefix(@Nonnull String awsS3Prefix) { + if (awsS3Prefix == null) + throw new IllegalArgumentException("null Amazon AWS S3 domain prefix"); + if (!Utils.AWS_S3_PREFIX_REGEX.matcher(awsS3Prefix).find()) { + throw new IllegalArgumentException("invalid Amazon AWS S3 domain prefix " + awsS3Prefix); + } + this.awsS3Prefix = awsS3Prefix; + } + + private String buildAwsUrl( + okhttp3.HttpUrl.Builder builder, + String bucketName, + boolean enforcePathStyle, + String region) { + String host = this.awsS3Prefix + this.awsDomainSuffix; + if (host.equals("s3-external-1.amazonaws.com") + || host.equals("s3-us-gov-west-1.amazonaws.com") + || host.equals("s3-fips-us-gov-west-1.amazonaws.com")) { + builder.host(host); + return host; + } + + host = this.awsS3Prefix; + if (this.awsS3Prefix.contains("s3-accelerate")) { + if (bucketName.contains(".")) { + throw new IllegalArgumentException( + "bucket name '" + bucketName + "' with '.' is not allowed for accelerate endpoint"); + } + if (enforcePathStyle) host = host.replaceFirst("-accelerate", ""); + } + + if (this.awsDualstack) host += "dualstack."; + if (!this.awsS3Prefix.contains("s3-accelerate")) host += region + "."; + host += this.awsDomainSuffix; + + builder.host(host); + return host; + } + + private String buildListBucketsUrl(okhttp3.HttpUrl.Builder builder, String region) { + if (this.awsDomainSuffix == null) return null; + + String host = this.awsS3Prefix + this.awsDomainSuffix; + if (host.equals("s3-external-1.amazonaws.com") + || host.equals("s3-us-gov-west-1.amazonaws.com") + || host.equals("s3-fips-us-gov-west-1.amazonaws.com")) { + builder.host(host); + return host; + } + + String s3Prefix = this.awsS3Prefix; + String domainSuffix = this.awsDomainSuffix; + if (this.awsS3Prefix.startsWith("s3.") || this.awsS3Prefix.startsWith("s3-")) { + s3Prefix = "s3."; + domainSuffix = "amazonaws.com" + (domainSuffix.endsWith(".cn") ? ".cn" : ""); + } + + host = s3Prefix + region + "." + domainSuffix; + builder.host(host); + return host; + } + + /** Build URL for given parameters. */ + public okhttp3.HttpUrl buildUrl( + Method method, + String bucketName, + String objectName, + String region, + QueryParameters queryParams) + throws MinioException { + if (bucketName == null && objectName != null) { + throw new IllegalArgumentException("null bucket name for object '" + objectName + "'"); + } + + okhttp3.HttpUrl.Builder urlBuilder = this.url.newBuilder(); + + if (queryParams != null) { + for (Map.Entry entry : queryParams.entries()) { + urlBuilder.addEncodedQueryParameter( + Utils.encode(entry.getKey()), Utils.encode(entry.getValue())); + } + } + + if (bucketName == null) { + this.buildListBucketsUrl(urlBuilder, region); + return urlBuilder.build(); + } + + boolean enforcePathStyle = ( + // use path style for make bucket to workaround "AuthorizationHeaderMalformed" error from + // s3.amazonaws.com + (method == Method.PUT && objectName == null && queryParams == null) + + // use path style for location query + || (queryParams != null && queryParams.containsKey("location")) + + // use path style where '.' in bucketName causes SSL certificate validation error + || (bucketName.contains(".") && this.url.isHttps())); + + String host = this.url.host(); + if (this.awsDomainSuffix != null) { + host = this.buildAwsUrl(urlBuilder, bucketName, enforcePathStyle, region); + } + + if (enforcePathStyle || !this.useVirtualStyle) { + urlBuilder.addEncodedPathSegment(Utils.encode(bucketName)); + } else { + urlBuilder.host(bucketName + "." + host); + } + + if (objectName != null) { + urlBuilder.addEncodedPathSegments(Utils.encodePath(objectName)); + } + + return urlBuilder.build(); + } + + @Override + public String toString() { + return url.toString(); + } + } + + public static MediaType mediaType(String value) { + if (value == null) return DEFAULT_MEDIA_TYPE; + MediaType mediaType = MediaType.parse(value); + if (mediaType == null) { + throw new IllegalArgumentException( + "invalid media/content type '" + value + "' as per RFC 2045"); + } + return mediaType; + } + + private static OkHttpClient enableJKSPKCS12Certificates( + OkHttpClient httpClient, + String trustStorePath, + String trustStorePassword, + String keyStorePath, + String keyStorePassword, + String keyStoreType) + throws MinioException { + try { + if (trustStorePath == null || trustStorePath.isEmpty()) { + throw new IllegalArgumentException("trust store path must be provided"); + } + if (trustStorePassword == null) { + throw new IllegalArgumentException("trust store password must be provided"); + } + if (keyStorePath == null || keyStorePath.isEmpty()) { + throw new IllegalArgumentException("key store path must be provided"); + } + if (keyStorePassword == null) { + throw new IllegalArgumentException("key store password must be provided"); + } + + SSLContext sslContext = SSLContext.getInstance("TLS"); + KeyStore trustStore = KeyStore.getInstance("JKS"); + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + try (InputStream trustInput = Files.newInputStream(Paths.get(trustStorePath)); + InputStream keyInput = Files.newInputStream(Paths.get(keyStorePath)); ) { + trustStore.load(trustInput, trustStorePassword.toCharArray()); + keyStore.load(keyInput, keyStorePassword.toCharArray()); + } + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(trustStore); + + KeyManagerFactory keyManagerFactory = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, keyStorePassword.toCharArray()); + + sslContext.init( + keyManagerFactory.getKeyManagers(), + trustManagerFactory.getTrustManagers(), + new java.security.SecureRandom()); + + return httpClient + .newBuilder() + .sslSocketFactory( + sslContext.getSocketFactory(), + (X509TrustManager) trustManagerFactory.getTrustManagers()[0]) + .build(); + } catch (GeneralSecurityException | IOException e) { + throw new MinioException(e); + } + } + + public static OkHttpClient enableJKSCertificates( + OkHttpClient httpClient, + String trustStorePath, + String trustStorePassword, + String keyStorePath, + String keyStorePassword) + throws MinioException { + return enableJKSPKCS12Certificates( + httpClient, trustStorePath, trustStorePassword, keyStorePath, keyStorePassword, "JKS"); + } + + public static OkHttpClient enablePKCS12Certificates( + OkHttpClient httpClient, + String trustStorePath, + String trustStorePassword, + String keyStorePath, + String keyStorePassword) + throws MinioException { + return enableJKSPKCS12Certificates( + httpClient, trustStorePath, trustStorePassword, keyStorePath, keyStorePassword, "PKCS12"); + } + + /** + * copied logic from + * https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java + */ + public static OkHttpClient enableExternalCertificates(OkHttpClient httpClient, String filename) + throws MinioException { + try { + Collection certificates = null; + try (InputStream inputStream = Files.newInputStream(Paths.get(filename))) { + certificates = CertificateFactory.getInstance("X.509").generateCertificates(inputStream); + } + + if (certificates == null || certificates.isEmpty()) { + throw new IllegalArgumentException("expected non-empty set of trusted certificates"); + } + + char[] password = "password".toCharArray(); // Any password will work. + + // Put the certificates a key store. + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + // By convention, 'null' creates an empty key store. + keyStore.load(null, password); + + int index = 0; + for (Certificate certificate : certificates) { + String certificateAlias = Integer.toString(index++); + keyStore.setCertificateEntry(certificateAlias, certificate); + } + + // Use it to build an X509 trust manager. + KeyManagerFactory keyManagerFactory = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, password); + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + + final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); + final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, null); + SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + return httpClient + .newBuilder() + .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0]) + .build(); + } catch (GeneralSecurityException | IOException e) { + throw new MinioException(e); + } + } + + public static OkHttpClient newDefaultClient() { + OkHttpClient httpClient = + new OkHttpClient() + .newBuilder() + .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS) + .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS) + .readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS) + .protocols(Arrays.asList(Protocol.HTTP_1_1)) + .build(); + String filename = System.getenv("SSL_CERT_FILE"); + if (filename != null && !filename.isEmpty()) { + try { + httpClient = enableExternalCertificates(httpClient, filename); + } catch (MinioException e) { + throw new RuntimeException(e); + } + } + return httpClient; + } + + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SIC", + justification = "Should not be used in production anyways.") + public static OkHttpClient disableCertCheck(OkHttpClient client) throws MinioException { + try { + final TrustManager[] trustAllCerts = + new TrustManager[] { + new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException {} + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException {} + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; + } + } + }; + + final SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + return client + .newBuilder() + .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]) + .hostnameVerifier( + new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }) + .build(); + } catch (KeyManagementException | NoSuchAlgorithmException e) { + throw new MinioException(e); + } + } + + public static OkHttpClient setTimeout( + OkHttpClient client, long connectTimeout, long writeTimeout, long readTimeout) { + return client + .newBuilder() + .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS) + .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS) + .readTimeout(readTimeout, TimeUnit.MILLISECONDS) + .build(); + } + + /** HTTP body of {@link RandomAccessFile}, {@link ByteBuffer} or {@link byte} array. */ + public static class Body { + private okhttp3.RequestBody requestBody; + private RandomAccessFile file; + private ByteBuffer buffer; + private byte[] data; + private Long length; + private MediaType contentType; + private String sha256Hash; + private String md5Hash; + private boolean bodyString; + + public Body(okhttp3.RequestBody requestBody) { + this.requestBody = requestBody; + this.contentType = requestBody.contentType(); + } + + public Body( + RandomAccessFile file, + long length, + MediaType contentType, + String sha256Hash, + String md5Hash) { + if (length < 0) throw new IllegalArgumentException("valid length must be provided"); + this.file = file; + set(length, contentType, sha256Hash, md5Hash); + } + + public Body(byte[] data, int length, MediaType contentType, String sha256Hash, String md5Hash) { + if (length < 0) throw new IllegalArgumentException("valid length must be provided"); + this.data = data; + set((long) length, contentType, sha256Hash, md5Hash); + } + + public Body(Object body, MediaType contentType, String sha256Hash, String md5Hash) + throws MinioException { + if (body instanceof ByteBuffer) { + this.buffer = (ByteBuffer) body; + set(null, contentType, sha256Hash, md5Hash); + return; + } + + byte[] data = null; + if (body instanceof CharSequence) { + data = ((CharSequence) body).toString().getBytes(StandardCharsets.UTF_8); + } else { + // For any other object, do XML marshalling. + data = Xml.marshal(body).getBytes(StandardCharsets.UTF_8); + contentType = XML_MEDIA_TYPE; + } + sha256Hash = Checksum.hexString(Checksum.SHA256.sum(data)); + md5Hash = Checksum.base64String(Checksum.MD5.sum(data)); + + this.bodyString = true; + this.data = data; + set((long) data.length, contentType, sha256Hash, md5Hash); + } + + private void set(Long length, MediaType contentType, String sha256Hash, String md5Hash) { + this.length = length; + this.contentType = contentType == null ? DEFAULT_MEDIA_TYPE : contentType; + this.sha256Hash = sha256Hash; + this.md5Hash = md5Hash; + } + + public MediaType contentType() { + return contentType; + } + + public String sha256Hash() { + return sha256Hash; + } + + public String md5Hash() { + return md5Hash; + } + + public boolean isHttpRequestBody() { + return requestBody != null; + } + + public Headers headers() { + Headers headers = new Headers(Headers.CONTENT_TYPE, contentType.toString()); + if (sha256Hash != null) headers.put(Headers.X_AMZ_CONTENT_SHA256, sha256Hash); + if (md5Hash != null) headers.put(Headers.CONTENT_MD5, md5Hash); + return headers; + } + + public RequestBody toRequestBody() throws MinioException { + if (requestBody != null) return new RequestBody(requestBody); + if (file != null) return new RequestBody(file, length, contentType); + if (buffer != null) return new RequestBody(buffer, contentType); + return new RequestBody(data, length.intValue(), contentType); + } + + @Override + public String toString() { + return bodyString ? new String(data, StandardCharsets.UTF_8) : "<<>>"; + } + } + + /** HTTP request body of {@link RandomAccessFile}, {@link ByteBuffer} or {@link byte} array. */ + public static class RequestBody extends okhttp3.RequestBody { + private okhttp3.RequestBody body; + private ByteBuffer buffer; + private RandomAccessFile file; + private long position; + private byte[] bytes; + private long length; + private MediaType contentType; + + public RequestBody( + @Nonnull final byte[] bytes, final int length, @Nonnull final MediaType contentType) { + this.bytes = Utils.validateNotNull(bytes, "data bytes"); + if (length < 0) throw new IllegalArgumentException("length must not be negative value"); + this.length = length; + this.contentType = Utils.validateNotNull(contentType, "content type"); + } + + public RequestBody( + @Nonnull final RandomAccessFile file, + final long length, + @Nonnull final MediaType contentType) + throws MinioException { + this.file = Utils.validateNotNull(file, "randome access file"); + if (length < 0) throw new IllegalArgumentException("length must not be negative value"); + this.length = length; + this.contentType = Utils.validateNotNull(contentType, "content type"); + try { + this.position = file.getFilePointer(); + } catch (IOException e) { + throw new MinioException(e); + } + } + + public RequestBody(@Nonnull final ByteBuffer buffer, @Nonnull final MediaType contentType) { + this.buffer = Utils.validateNotNull(buffer, "buffer"); + this.length = buffer.length(); + this.contentType = Utils.validateNotNull(contentType, "content type"); + } + + public RequestBody(@Nonnull final okhttp3.RequestBody body) throws MinioException { + try { + this.body = Utils.validateNotNull(body, "body"); + if (body.contentLength() < 0) { + throw new IllegalArgumentException("length must not be negative value"); + } + this.length = body.contentLength(); + this.contentType = Utils.validateNotNull(body.contentType(), "content type"); + } catch (IOException e) { + throw new MinioException(e); + } + } + + @Override + public MediaType contentType() { + return contentType; + } + + @Override + public long contentLength() { + return length; + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + if (body != null) { + body.writeTo(sink); + } else if (buffer != null) { + sink.write(Okio.source(buffer.inputStream()), length); + } else if (file != null) { + file.seek(position); + sink.write(Okio.source(Channels.newInputStream(file.getChannel())), length); + } else { + sink.write(bytes, 0, (int) length); + } + } + } + + /** HTTP methods. */ + public static enum Method { + GET, + HEAD, + POST, + PUT, + DELETE; + } + + /** HTTP headers. */ + public static class Headers implements Iterable> { + private static final long serialVersionUID = -8099023918647559669L; + + public static final String ACCEPT_ENCODING = "Accept-Encoding"; + public static final String AUTHORIZATION = "Authorization"; + public static final String CONTENT_ENCODING = "Content-Encoding"; + public static final String CONTENT_LENGTH = "Content-Length"; + public static final String CONTENT_MD5 = "Content-Md5"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String HOST = "Host"; + public static final String USER_AGENT = "User-Agent"; + public static final String X_AMZ_CHECKSUM_SHA256 = "x-amz-checksum-sha256"; + public static final String X_AMZ_CONTENT_SHA256 = "X-Amz-Content-Sha256"; + public static final String X_AMZ_COPY_SOURCE_RANGE = "x-amz-copy-source-range"; + public static final String X_AMZ_DATE = "X-Amz-Date"; + public static final String X_AMZ_SDK_CHECKSUM_ALGORITHM = "X-Amz-Sdk-Checksum-Algorithm"; + public static final String X_AMZ_SECURITY_TOKEN = "X-Amz-Security-Token"; + + private static final Set NON_EMPTY_HEADERS = + ImmutableSet.of( + ACCEPT_ENCODING, + AUTHORIZATION, + CONTENT_ENCODING, + CONTENT_LENGTH, + CONTENT_MD5, + CONTENT_TYPE, + HOST, + USER_AGENT, + X_AMZ_CHECKSUM_SHA256, + X_AMZ_CONTENT_SHA256, + X_AMZ_DATE, + X_AMZ_SDK_CHECKSUM_ALGORITHM, + X_AMZ_SECURITY_TOKEN); + private final Map> headers = new HashMap<>(); + + // Normalize header names to Title-Case + private String normalize(String name) { + String[] parts = name.toLowerCase(Locale.US).split("-", -1); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (!part.isEmpty()) { + sb.append(Character.toUpperCase(part.charAt(0))); + if (part.length() > 1) { + sb.append(part.substring(1)); + } + } + if (i < parts.length - 1) { + sb.append("-"); + } + } + return sb.toString(); + } + + public Headers() {} + + public Headers(Headers source) { + if (source != null) putAll(source); + } + + public Headers(Map source) { + if (source != null) putAll(source); + } + + public Headers(Multimap source) { + if (source != null) putAll(source); + } + + public Headers(String... keysAndValues) { + if (keysAndValues.length % 2 != 0) { + throw new IllegalArgumentException("Expected alternating keys and values"); + } + for (int i = 0; i < keysAndValues.length; i += 2) { + set(keysAndValues[i], keysAndValues[i + 1]); + } + } + + public static Headers merge(Headers... headersList) { + Headers headers = new Headers(); + for (Headers h : headersList) headers.putAll(h); + return headers; + } + + private String validateName(String name) { + if (!Utils.validateNotNull(name, "name").trim().equals(name)) { + throw new IllegalArgumentException("leading/trailing spaces are not allowed in name"); + } + if (name.isEmpty()) throw new IllegalArgumentException("name must not be empty"); + return normalize(name); + } + + private String validateValue(String name, String value) { + Utils.validateNotNull(value, "value"); + if (NON_EMPTY_HEADERS.contains(name) && value.isEmpty()) { + throw new IllegalArgumentException("value must not be empty for name " + name); + } + if (CONTENT_TYPE.equals(name) && MediaType.parse(value) == null) { + throw new IllegalArgumentException("invalid content type '" + value + "' as per RFC 2045"); + } + return value; + } + + public void add(@Nonnull String name, @Nonnull String value) { + name = validateName(name); + value = validateValue(name, value); + headers.computeIfAbsent(name, k -> new HashSet<>()).add(value); + } + + public void set(@Nonnull String name, @Nonnull String value) { + name = validateName(name); + value = validateValue(name, value); + headers.put(name, new HashSet<>(Collections.singletonList(value))); + } + + public String getFirst(String name) { + if (name == null) return null; + Set values = get(name); + return values.isEmpty() ? null : values.iterator().next(); + } + + public boolean contains(String name) { + if (name == null) return false; + return headers.containsKey(normalize(name)); + } + + public boolean namePrefixAny(String prefix) { + if (prefix == null) return false; + final String finalPrefix = normalize(prefix); + return names().stream().anyMatch(name -> name.startsWith(finalPrefix)); + } + + public Set names() { + return Collections.unmodifiableSet(headers.keySet()); + } + + @Override + public Iterator> iterator() { + return entrySet().iterator(); + } + + @Override + public String toString() { + return headers.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Headers)) return false; + Headers headers = (Headers) o; + return Objects.equals(this.headers, headers.headers); + } + + @Override + public int hashCode() { + return Objects.hash(headers); + } + + public okhttp3.Headers toHttpHeaders() { + okhttp3.Headers.Builder builder = new okhttp3.Headers.Builder(); + if (containsKey(CONTENT_ENCODING)) { + builder.add( + CONTENT_ENCODING, + get(CONTENT_ENCODING).stream() + .distinct() + .filter(encoding -> !encoding.isEmpty()) + .collect(Collectors.joining(","))); + } + + for (Map.Entry entry : entries()) { + if (!entry.getKey().equals(CONTENT_ENCODING)) { + builder.addUnsafeNonAscii(entry.getKey(), entry.getValue()); + } + } + + return builder.build(); + } + + public void clear() { + headers.clear(); + } + + public boolean containsKey(String name) { + if (name == null) return false; + return headers.containsKey(normalize(name)); + } + + public Set> entrySet() { + Set> result = new LinkedHashSet<>(); + for (Map.Entry> entry : headers.entrySet()) { + for (String value : entry.getValue()) { + result.add(new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), value)); + } + } + return result; + } + + public Set> entries() { + return entrySet(); + } + + public Set get(String name) { + if (name == null) name = ""; + return headers.getOrDefault(normalize(name), Collections.emptySet()); + } + + public Set keySet() { + return names(); + } + + public boolean put(@Nonnull String name, @Nonnull String value) { + add(name, value); + return true; + } + + public Headers putAll(Map source) { + if (source == null) return this; + for (Map.Entry entry : source.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + public Headers putAll(Multimap source) { + if (source == null) return this; + for (Map.Entry entry : source.entries()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + public Headers putAll(Headers source) { + if (source == null) return this; + for (Map.Entry entry : source.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + public Headers putAll(@Nonnull String name, @Nonnull Set values) { + Utils.validateNotNull(values, "value"); + for (String value : values) put(name, value); + return this; + } + + public Headers putAll(@Nonnull String name, @Nonnull List values) { + Utils.validateNotNull(values, "value"); + for (String value : values) put(name, value); + return this; + } + + public Set remove(String name) { + if (name == null) name = ""; + return headers.remove(normalize(name)); + } + + public boolean remove(String name, String value) { + if (name == null) return false; + name = normalize(name); + return headers.containsKey(name) ? headers.get(name).remove(value) : false; + } + + public boolean removeAll(String name) { + return remove(name) != null; + } + + public int size() { + return headers.size(); + } + } + + /** HTTP query parameters. */ + public static class QueryParameters implements Iterable> { + private static final long serialVersionUID = 5193347714796984439L; + + private final Map> parameters = new HashMap<>(); + + public QueryParameters() {} + + public QueryParameters(QueryParameters source) { + if (source != null) putAll(source); + } + + public QueryParameters(Map source) { + if (source != null) putAll(source); + } + + public QueryParameters(Multimap source) { + if (source != null) putAll(source); + } + + public QueryParameters(String... keysAndValues) { + if (keysAndValues.length % 2 != 0) { + throw new IllegalArgumentException("Expected alternating keys and values"); + } + for (int i = 0; i < keysAndValues.length; i += 2) { + set(keysAndValues[i], keysAndValues[i + 1]); + } + } + + public static QueryParameters merge(QueryParameters... queryParamsList) { + QueryParameters queryParams = new QueryParameters(); + for (QueryParameters q : queryParamsList) queryParams.putAll(q); + return queryParams; + } + + public void add(@Nonnull String key, @Nonnull String value) { + Utils.validateNotEmptyString(key, "key"); + if (value == null) value = ""; + parameters.computeIfAbsent(key, k -> new ArrayList<>()).add(value); + } + + public void set(@Nonnull String key, @Nonnull String value) { + Utils.validateNotEmptyString(key, "key"); + if (value == null) value = ""; + parameters.put(key, new ArrayList<>(Collections.singletonList(value))); + } + + public String getFirst(String key) { + if (key == null) return null; + List values = get(key); + return values.isEmpty() ? null : values.get(0); + } + + public boolean contains(String key) { + if (key == null) return false; + return parameters.containsKey(key); + } + + public boolean keyPrefixAny(String prefix) { + if (prefix == null) return false; + return keys().stream().anyMatch(key -> key.startsWith(prefix)); + } + + public Set keys() { + return Collections.unmodifiableSet(parameters.keySet()); + } + + @Override + public Iterator> iterator() { + return entrySet().iterator(); + } + + @Override + public String toString() { + return parameters.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof QueryParameters)) return false; + QueryParameters queryParams = (QueryParameters) o; + return Objects.equals(this.parameters, queryParams.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(parameters); + } + + public void clear() { + parameters.clear(); + } + + public boolean containsKey(String key) { + if (key == null) return false; + return parameters.containsKey(key); + } + + public Set> entrySet() { + Set> result = new LinkedHashSet<>(); + for (Map.Entry> entry : parameters.entrySet()) { + for (String value : entry.getValue()) { + result.add(new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), value)); + } + } + return result; + } + + public Set> entries() { + return entrySet(); + } + + public List get(String key) { + if (key == null) key = ""; + return parameters.getOrDefault(key, Collections.emptyList()); + } + + public Set keySet() { + return keys(); + } + + public boolean put(@Nonnull String key, @Nonnull String value) { + add(key, value); + return true; + } + + public QueryParameters putAll(Map source) { + if (source == null) return this; + for (Map.Entry entry : source.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + public QueryParameters putAll(Multimap source) { + if (source == null) return this; + for (Map.Entry entry : source.entries()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + public QueryParameters putAll(QueryParameters source) { + if (source == null) return this; + for (Map.Entry entry : source.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + public QueryParameters putAll(@Nonnull String key, @Nonnull List values) { + Utils.validateNotNull(values, "value"); + for (String value : values) put(key, value); + return this; + } + + public List remove(String key) { + if (key == null) key = ""; + return parameters.remove(key); + } + + public boolean remove(String key, String value) { + if (key == null) return false; + return parameters.containsKey(key) ? parameters.get(key).remove(value) : false; + } + + public boolean removeAll(String key) { + return remove(key) != null; + } + + public int size() { + return parameters.size(); + } + } + + /** HTTP request. */ + public static class Request { + private okhttp3.Request httpRequest; + private String httpTraces; + + public Request(okhttp3.Request httpRequest, String httpTraces) { + this.httpRequest = httpRequest; + this.httpTraces = httpTraces; + } + + public okhttp3.Request httpRequest() { + return httpRequest; + } + + public String httpTraces() { + return httpTraces; + } + } + + /** S3 request. */ + public static class S3Request { + private String userAgent; + private Method method; + private BaseArgs args; + private Headers headers; + private QueryParameters queryParams; + private Body body; + + private String bucket; + private String region; + private String object; + + private S3Request(Builder builder) { + this.userAgent = builder.userAgent; + this.method = builder.method; + this.args = builder.args; + this.headers = builder.headers; + this.queryParams = builder.queryParams; + this.body = builder.body; + + if (args != null) { + this.headers = Headers.merge(args.extraHeaders(), builder.headers); + this.queryParams = QueryParameters.merge(args.extraQueryParams(), builder.queryParams); + + if (args instanceof BucketArgs) { + this.bucket = ((BucketArgs) args).bucket(); + this.region = ((BucketArgs) args).region(); + } + if (args instanceof ObjectArgs) this.object = ((ObjectArgs) args).object(); + } + } + + public String userAgent() { + return userAgent; + } + + public Method method() { + return method; + } + + public BaseArgs args() { + return args; + } + + public Headers headers() { + return headers; + } + + public QueryParameters queryParams() { + return queryParams; + } + + public String bucket() { + return bucket; + } + + public String region() { + return region; + } + + public String object() { + return object; + } + + private Request toRequest( + BaseUrl baseUrl, String region, Credentials credentials, Integer expiry) + throws MinioException { + if (region == null) region = this.region; + if (region == null) region = US_EAST_1; + + okhttp3.HttpUrl url = baseUrl.buildUrl(method, bucket, object, region, queryParams); + + Body body = this.body; + if (body == null) { + body = + headers.containsKey(Headers.CONTENT_TYPE) + ? new Body( + ZERO_BODY, + 0, + MediaType.parse(headers.getFirst(Headers.CONTENT_TYPE)), + Checksum.ZERO_SHA256_HASH, + Checksum.ZERO_MD5_HASH) + : EMPTY_BODY; + } + + String sha256Hash = null; + if (!body.isHttpRequestBody()) { + if (credentials == null) { + if (body.md5Hash() == null) { + throw new IllegalArgumentException("MD5 hash must be provided to request body"); + } + } else if (!url.isHttps()) { + if (body.sha256Hash() == null) { + throw new IllegalArgumentException("SHA256 hash must be provided to request body"); + } + } else if (body.sha256Hash() == null) { + sha256Hash = Checksum.UNSIGNED_PAYLOAD; + } + } + + okhttp3.RequestBody requestBody = body.toRequestBody(); + + Headers headers = Headers.merge(this.headers, body.headers()); + if (sha256Hash != null) headers.put(Headers.X_AMZ_CONTENT_SHA256, sha256Hash); + if (credentials != null) { + String sessionToken = credentials.sessionToken(); + if (sessionToken != null) headers.put(Headers.X_AMZ_SECURITY_TOKEN, sessionToken); + headers.put(Headers.X_AMZ_DATE, ZonedDateTime.now().format(Time.AMZ_DATE_FORMAT)); + } + // Disable default okhttp gzip compression + headers.put(Headers.ACCEPT_ENCODING, "identity"); + headers.put(Headers.USER_AGENT, userAgent); + headers.put(Headers.HOST, Utils.getHostHeader(url)); + if (method == Method.PUT || method == Method.POST) { + headers.put(Headers.CONTENT_TYPE, body.contentType().toString()); + try { + headers.put(Headers.CONTENT_LENGTH, String.valueOf(requestBody.contentLength())); + } catch (IOException e) { + throw new MinioException(e); + } + } else { + headers.remove(Headers.CONTENT_TYPE); + } + + if (expiry != null) { + headers.remove(Headers.CONTENT_LENGTH); + headers.remove(Headers.CONTENT_TYPE); + } + + okhttp3.Request request = + new okhttp3.Request.Builder() + .url(url) + .headers(headers.toHttpHeaders()) + .method( + method.toString(), + (method == Method.PUT || method == Method.POST) ? requestBody : null) + .build(); + if (!body.isHttpRequestBody()) { + if (credentials != null) { + if (expiry == null) { + request = + Signer.signV4S3( + request, + region, + credentials.accessKey(), + credentials.secretKey(), + sha256Hash != null ? sha256Hash : body.sha256Hash()); + } else { + okhttp3.HttpUrl signedUrl = + Signer.presignV4( + request, region, credentials.accessKey(), credentials.secretKey(), expiry); + request = request.newBuilder().url(signedUrl).build(); + } + } + } + + StringBuilder traceBuilder = new StringBuilder(); + traceBuilder.append("---------START-HTTP---------\n"); + String encodedPath = request.url().encodedPath(); + String encodedQuery = request.url().encodedQuery(); + if (encodedQuery != null) encodedPath += "?" + encodedQuery; + traceBuilder.append(request.method()).append(" ").append(encodedPath).append(" HTTP/1.1\n"); + traceBuilder.append( + request + .headers() + .toString() + .replaceAll("Signature=([0-9a-f]+)", "Signature=*REDACTED*") + .replaceAll("Credential=([^/]+)", "Credential=*REDACTED*")); + String lastTwoChars = traceBuilder.substring(traceBuilder.length() - 2); + if (lastTwoChars.charAt(1) != '\n') { + traceBuilder.append("\n\n"); + } else if (lastTwoChars.charAt(0) != '\n') { + traceBuilder.append("\n"); + } + String value = body.toString(); + if (method == Method.PUT || method == Method.POST) { + traceBuilder.append(value); + if (!value.endsWith("\n")) traceBuilder.append("\n"); + } + + return new Request(request, traceBuilder.toString()); + } + + public Request toRequest(BaseUrl baseUrl, String region, Credentials credentials) + throws MinioException { + return toRequest(baseUrl, region, credentials, null); + } + + public Request toPresignedRequest( + BaseUrl baseUrl, String region, Credentials credentials, int expiry) throws MinioException { + return toRequest(baseUrl, region, credentials, expiry); + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link S3Request}. */ + public static class Builder { + private String userAgent; + private Method method; + private BaseArgs args; + private Headers headers; + private QueryParameters queryParams; + private Body body; + + public Builder userAgent(String userAgent) { + this.userAgent = Utils.validateNotNull(userAgent, "user agent"); + return this; + } + + public Builder method(Method method) { + this.method = Utils.validateNotNull(method, "HTTP method"); + return this; + } + + public Builder args(BaseArgs args) { + this.args = args; + return this; + } + + public Builder headers(Headers headers) { + this.headers = headers; + return this; + } + + public Builder queryParams(QueryParameters queryParams) { + this.queryParams = queryParams; + return this; + } + + public Builder body(Body body) { + this.body = body; + return this; + } + + public S3Request build() { + if (userAgent == null) throw new IllegalArgumentException("user agent must be provided"); + if (method == null) throw new IllegalArgumentException("method must be provided"); + return new S3Request(this); + } + } + } +} diff --git a/api/src/main/java/io/minio/HttpRequestBody.java b/api/src/main/java/io/minio/HttpRequestBody.java deleted file mode 100644 index cbc59706c..000000000 --- a/api/src/main/java/io/minio/HttpRequestBody.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio; - -import java.io.IOException; -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okio.BufferedSink; - -/** RequestBody that wraps a single data object. */ -class HttpRequestBody extends RequestBody { - private PartSource partSource; - private byte[] bytes; - private int length; - private String contentType; - - HttpRequestBody(final PartSource partSource, final String contentType) { - this.partSource = partSource; - this.contentType = contentType; - } - - HttpRequestBody(final byte[] bytes, final int length, final String contentType) { - this.bytes = bytes; - this.length = length; - this.contentType = contentType; - } - - @Override - public MediaType contentType() { - MediaType mediaType = null; - if (contentType != null) mediaType = MediaType.parse(contentType); - return (mediaType == null) ? MediaType.parse("application/octet-stream") : mediaType; - } - - @Override - public long contentLength() { - return (partSource != null) ? partSource.size() : length; - } - - @Override - public void writeTo(BufferedSink sink) throws IOException { - if (partSource != null) { - sink.write(partSource.source(), partSource.size()); - } else { - sink.write(bytes, 0, length); - } - } -} diff --git a/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java b/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java index 4b2a1adfd..6a435ef1f 100644 --- a/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java +++ b/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java @@ -17,7 +17,7 @@ package io.minio; /** - * Argument class of {@link MinioAsyncClient#isObjectLegalHoldEnabled} and {@link + * Arguments of {@link MinioAsyncClient#isObjectLegalHoldEnabled} and {@link * MinioClient#isObjectLegalHoldEnabled}. */ public class IsObjectLegalHoldEnabledArgs extends ObjectVersionArgs { @@ -25,7 +25,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link IsObjectLegalHoldEnabledArgs}. */ + /** Builder of {@link IsObjectLegalHoldEnabledArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/ListBucketsArgs.java b/api/src/main/java/io/minio/ListBucketsArgs.java index 539e4192f..a3fc9ad5b 100644 --- a/api/src/main/java/io/minio/ListBucketsArgs.java +++ b/api/src/main/java/io/minio/ListBucketsArgs.java @@ -18,7 +18,10 @@ import java.util.Objects; -/** Argument class of {@link MinioAsyncClient#listBuckets} and {@link MinioClient#listBuckets}. */ +/** + * Arguments of {@link BaseS3Client#listBucketsAPI}, {@link MinioAsyncClient#listBuckets} and {@link + * MinioClient#listBuckets}. + */ public class ListBucketsArgs extends BaseArgs { private String bucketRegion; private int maxBuckets = 10000; @@ -45,13 +48,13 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link ListBucketsArgs}. */ + /** Builder of {@link ListBucketsArgs}. */ public static final class Builder extends BaseArgs.Builder { @Override protected void validate(ListBucketsArgs args) {} public Builder bucketRegion(String region) { - validateNullOrNotEmptyString(region, "bucket region"); + Utils.validateNullOrNotEmptyString(region, "bucket region"); operations.add(args -> args.bucketRegion = region); return this; } @@ -66,13 +69,13 @@ public Builder maxBuckets(int maxBuckets) { } public Builder prefix(String prefix) { - validateNullOrNotEmptyString(prefix, "prefix"); + Utils.validateNullOrNotEmptyString(prefix, "prefix"); operations.add(args -> args.prefix = prefix); return this; } public Builder continuationToken(String continuationToken) { - validateNullOrNotEmptyString(continuationToken, "continuation token"); + Utils.validateNullOrNotEmptyString(continuationToken, "continuation token"); operations.add(args -> args.continuationToken = continuationToken); return this; } diff --git a/api/src/main/java/io/minio/ListBucketsResponse.java b/api/src/main/java/io/minio/ListBucketsResponse.java index 1914a01a0..99ebd063b 100644 --- a/api/src/main/java/io/minio/ListBucketsResponse.java +++ b/api/src/main/java/io/minio/ListBucketsResponse.java @@ -19,7 +19,7 @@ import io.minio.messages.ListAllMyBucketsResult; import okhttp3.Headers; -/** Response class of {@link S3Base#listBucketsAsync}. */ +/** Response of {@link BaseS3Client#listBucketsAPI}. */ public class ListBucketsResponse extends GenericResponse { private ListAllMyBucketsResult result; diff --git a/api/src/main/java/io/minio/ListMultipartUploadsArgs.java b/api/src/main/java/io/minio/ListMultipartUploadsArgs.java new file mode 100644 index 000000000..a059080a1 --- /dev/null +++ b/api/src/main/java/io/minio/ListMultipartUploadsArgs.java @@ -0,0 +1,114 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#listMultipartUploads}. */ +public class ListMultipartUploadsArgs extends BucketArgs { + private String delimiter; + private String encodingType; + private Integer maxUploads; + private String prefix; + private String keyMarker; + private String uploadIdMarker; + + public String delimiter() { + return delimiter; + } + + public String encodingType() { + return encodingType; + } + + public Integer maxUploads() { + return maxUploads; + } + + public String prefix() { + return prefix; + } + + public String keyMarker() { + return keyMarker; + } + + public String uploadIdMarker() { + return uploadIdMarker; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link ListMultipartUploadsArgs}. */ + public static final class Builder extends BucketArgs.Builder { + public Builder delimiter(String delimiter) { + operations.add(args -> args.delimiter = delimiter); + return this; + } + + public Builder encodingType(String encodingType) { + operations.add(args -> args.encodingType = encodingType); + return this; + } + + public Builder maxUploads(Integer maxUploads) { + if (maxUploads != null && maxUploads < 1) { + throw new IllegalArgumentException("valid max keys must be provided"); + } + + operations.add(args -> args.maxUploads = maxUploads); + return this; + } + + public Builder prefix(String prefix) { + operations.add(args -> args.prefix = prefix); + return this; + } + + public Builder keyMarker(String keyMarker) { + operations.add(args -> args.keyMarker = keyMarker); + return this; + } + + public Builder uploadIdMarker(String uploadIdMarker) { + operations.add(args -> args.uploadIdMarker = uploadIdMarker); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListMultipartUploadsArgs)) return false; + if (!super.equals(o)) return false; + ListMultipartUploadsArgs that = (ListMultipartUploadsArgs) o; + return Objects.equals(delimiter, that.delimiter) + && Objects.equals(encodingType, that.encodingType) + && Objects.equals(maxUploads, that.maxUploads) + && Objects.equals(prefix, that.prefix) + && Objects.equals(keyMarker, that.keyMarker) + && Objects.equals(uploadIdMarker, that.uploadIdMarker); + } + + @Override + public int hashCode() { + return Objects.hash( + super.hashCode(), delimiter, encodingType, maxUploads, prefix, keyMarker, uploadIdMarker); + } +} diff --git a/api/src/main/java/io/minio/ListMultipartUploadsResponse.java b/api/src/main/java/io/minio/ListMultipartUploadsResponse.java index 1fa6d6830..531bbb21e 100644 --- a/api/src/main/java/io/minio/ListMultipartUploadsResponse.java +++ b/api/src/main/java/io/minio/ListMultipartUploadsResponse.java @@ -19,7 +19,7 @@ import io.minio.messages.ListMultipartUploadsResult; import okhttp3.Headers; -/** Response class of {@link S3Base#listMultipartUploadsAsync}. */ +/** Response of {@link BaseS3Client#listMultipartUploads}. */ public class ListMultipartUploadsResponse extends GenericResponse { private ListMultipartUploadsResult result; diff --git a/api/src/main/java/io/minio/ListObjectVersionsArgs.java b/api/src/main/java/io/minio/ListObjectVersionsArgs.java new file mode 100644 index 000000000..3309a01d0 --- /dev/null +++ b/api/src/main/java/io/minio/ListObjectVersionsArgs.java @@ -0,0 +1,129 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#listObjectVersions}. */ +public class ListObjectVersionsArgs extends BucketArgs { + private String delimiter; + private String encodingType; + private Integer maxKeys; + private String prefix; + private String keyMarker; + private String versionIdMarker; + + protected ListObjectVersionsArgs() {} + + public ListObjectVersionsArgs(ListObjectsArgs args) { + this.extraHeaders = args.extraHeaders(); + this.extraQueryParams = args.extraQueryParams(); + this.bucketName = args.bucket(); + this.region = args.region(); + this.delimiter = args.delimiter(); + this.encodingType = args.useUrlEncodingType() ? "url" : null; + this.maxKeys = args.maxKeys(); + this.prefix = args.prefix(); + this.keyMarker = args.keyMarker(); + this.versionIdMarker = args.versionIdMarker(); + } + + public String delimiter() { + return delimiter; + } + + public String encodingType() { + return encodingType; + } + + public int maxKeys() { + return maxKeys; + } + + public String prefix() { + return prefix; + } + + public String keyMarker() { + return keyMarker; + } + + public String versionIdMarker() { + return versionIdMarker; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link ListObjectVersionsArgs}. */ + public static final class Builder extends BucketArgs.Builder { + public Builder delimiter(String delimiter) { + operations.add(args -> args.delimiter = delimiter); + return this; + } + + public Builder encodingType(String encodingType) { + operations.add(args -> args.encodingType = encodingType); + return this; + } + + public Builder maxKeys(Integer maxKeys) { + if (maxKeys != null && maxKeys < 1) { + throw new IllegalArgumentException("valid max keys must be provided"); + } + + operations.add(args -> args.maxKeys = maxKeys); + return this; + } + + public Builder prefix(String prefix) { + operations.add(args -> args.prefix = prefix); + return this; + } + + public Builder keyMarker(String keyMarker) { + operations.add(args -> args.keyMarker = keyMarker); + return this; + } + + public Builder versionIdMarker(String versionIdMarker) { + operations.add(args -> args.versionIdMarker = versionIdMarker); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListObjectVersionsArgs)) return false; + if (!super.equals(o)) return false; + ListObjectVersionsArgs that = (ListObjectVersionsArgs) o; + return Objects.equals(delimiter, that.delimiter) + && Objects.equals(encodingType, that.encodingType) + && Objects.equals(maxKeys, that.maxKeys) + && Objects.equals(prefix, that.prefix) + && Objects.equals(keyMarker, that.keyMarker) + && Objects.equals(versionIdMarker, that.versionIdMarker); + } + + @Override + public int hashCode() { + return Objects.hash( + super.hashCode(), delimiter, encodingType, maxKeys, prefix, keyMarker, versionIdMarker); + } +} diff --git a/api/src/main/java/io/minio/ListObjectVersionsResponse.java b/api/src/main/java/io/minio/ListObjectVersionsResponse.java index 399d1b513..6aea62745 100644 --- a/api/src/main/java/io/minio/ListObjectVersionsResponse.java +++ b/api/src/main/java/io/minio/ListObjectVersionsResponse.java @@ -19,7 +19,7 @@ import io.minio.messages.ListVersionsResult; import okhttp3.Headers; -/** Response class of {@link S3Base#listObjectVersionsAsync}. */ +/** Response of {@link BaseS3Client#listObjectVersions}. */ public class ListObjectVersionsResponse extends GenericResponse { private ListVersionsResult result; diff --git a/api/src/main/java/io/minio/ListObjectsArgs.java b/api/src/main/java/io/minio/ListObjectsArgs.java index 40231b6c3..7f31fea81 100644 --- a/api/src/main/java/io/minio/ListObjectsArgs.java +++ b/api/src/main/java/io/minio/ListObjectsArgs.java @@ -18,7 +18,7 @@ import java.util.Objects; -/** Argument class of {@link MinioAsyncClient#listObjects} and {@link MinioClient#listObjects}. */ +/** Arguments of {@link MinioAsyncClient#listObjects} and {@link MinioClient#listObjects}. */ public class ListObjectsArgs extends BucketArgs { private String delimiter = ""; private boolean useUrlEncodingType = true; @@ -97,7 +97,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link ListObjectsArgs}. */ + /** Builder of {@link ListObjectsArgs}. */ public static final class Builder extends BucketArgs.Builder { @Override protected void validate(ListObjectsArgs args) { @@ -128,7 +128,7 @@ public Builder useUrlEncodingType(boolean flag) { } public Builder keyMarker(String keyMarker) { - validateNullOrNotEmptyString(keyMarker, "key marker"); + Utils.validateNullOrNotEmptyString(keyMarker, "key marker"); operations.add(args -> args.keyMarker = keyMarker); return this; } @@ -158,7 +158,7 @@ public Builder prefix(String prefix) { } public Builder continuationToken(String continuationToken) { - validateNullOrNotEmptyString(continuationToken, "continuation token"); + Utils.validateNullOrNotEmptyString(continuationToken, "continuation token"); operations.add(args -> args.continuationToken = continuationToken); return this; } @@ -169,7 +169,7 @@ public Builder fetchOwner(boolean fetchOwner) { } public Builder versionIdMarker(String versionIdMarker) { - validateNullOrNotEmptyString(versionIdMarker, "version ID marker"); + Utils.validateNullOrNotEmptyString(versionIdMarker, "version ID marker"); operations.add(args -> args.versionIdMarker = versionIdMarker); return this; } diff --git a/api/src/main/java/io/minio/ListObjectsV1Args.java b/api/src/main/java/io/minio/ListObjectsV1Args.java new file mode 100644 index 000000000..9e086a787 --- /dev/null +++ b/api/src/main/java/io/minio/ListObjectsV1Args.java @@ -0,0 +1,116 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#listObjectsV1}. */ +public class ListObjectsV1Args extends BucketArgs { + private String delimiter; + private String encodingType; + private Integer maxKeys; + private String prefix; + private String marker; + + protected ListObjectsV1Args() {} + + public ListObjectsV1Args(ListObjectsArgs args) { + this.extraHeaders = args.extraHeaders(); + this.extraQueryParams = args.extraQueryParams(); + this.bucketName = args.bucket(); + this.region = args.region(); + this.delimiter = args.delimiter(); + this.encodingType = args.useUrlEncodingType() ? "url" : null; + this.maxKeys = args.maxKeys(); + this.prefix = args.prefix(); + this.marker = args.keyMarker(); + } + + public String delimiter() { + return delimiter; + } + + public String encodingType() { + return encodingType; + } + + public int maxKeys() { + return maxKeys; + } + + public String prefix() { + return prefix; + } + + public String marker() { + return marker; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link ListObjectsV1Args}. */ + public static final class Builder extends BucketArgs.Builder { + public Builder delimiter(String delimiter) { + operations.add(args -> args.delimiter = delimiter); + return this; + } + + public Builder encodingType(String encodingType) { + operations.add(args -> args.encodingType = encodingType); + return this; + } + + public Builder maxKeys(Integer maxKeys) { + if (maxKeys != null && maxKeys < 1) { + throw new IllegalArgumentException("valid max keys must be provided"); + } + + operations.add(args -> args.maxKeys = maxKeys); + return this; + } + + public Builder prefix(String prefix) { + operations.add(args -> args.prefix = prefix); + return this; + } + + public Builder marker(String marker) { + operations.add(args -> args.marker = marker); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListObjectsV1Args)) return false; + if (!super.equals(o)) return false; + ListObjectsV1Args that = (ListObjectsV1Args) o; + return Objects.equals(delimiter, that.delimiter) + && Objects.equals(encodingType, that.encodingType) + && Objects.equals(maxKeys, that.maxKeys) + && Objects.equals(prefix, that.prefix) + && Objects.equals(marker, that.marker); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), delimiter, encodingType, maxKeys, prefix, marker); + } +} diff --git a/api/src/main/java/io/minio/ListObjectsV1Response.java b/api/src/main/java/io/minio/ListObjectsV1Response.java index 201523ffa..34faf5d6b 100644 --- a/api/src/main/java/io/minio/ListObjectsV1Response.java +++ b/api/src/main/java/io/minio/ListObjectsV1Response.java @@ -19,7 +19,7 @@ import io.minio.messages.ListBucketResultV1; import okhttp3.Headers; -/** Response class of {@link S3Base#listObjectsV1Async}. */ +/** Response of {@link BaseS3Client#listObjectsV1}. */ public class ListObjectsV1Response extends GenericResponse { private ListBucketResultV1 result; diff --git a/api/src/main/java/io/minio/ListObjectsV2Args.java b/api/src/main/java/io/minio/ListObjectsV2Args.java new file mode 100644 index 000000000..9806ce7ee --- /dev/null +++ b/api/src/main/java/io/minio/ListObjectsV2Args.java @@ -0,0 +1,161 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#listObjectsV2}. */ +public class ListObjectsV2Args extends BucketArgs { + private String delimiter; + private String encodingType; + private Integer maxKeys; + private String prefix; + private String startAfter; + private String continuationToken; + private boolean fetchOwner; + private boolean includeUserMetadata; + + protected ListObjectsV2Args() {} + + public ListObjectsV2Args(ListObjectsArgs args) { + this.extraHeaders = args.extraHeaders(); + this.extraQueryParams = args.extraQueryParams(); + this.bucketName = args.bucket(); + this.region = args.region(); + this.delimiter = args.delimiter(); + this.encodingType = args.useUrlEncodingType() ? "url" : null; + this.maxKeys = args.maxKeys(); + this.prefix = args.prefix(); + this.startAfter = args.startAfter(); + this.continuationToken = args.continuationToken(); + this.fetchOwner = args.fetchOwner(); + this.includeUserMetadata = args.includeUserMetadata(); + } + + public String delimiter() { + return delimiter; + } + + public String encodingType() { + return encodingType; + } + + public int maxKeys() { + return maxKeys; + } + + public String prefix() { + return prefix; + } + + public String startAfter() { + return startAfter; + } + + public String continuationToken() { + return continuationToken; + } + + public boolean fetchOwner() { + return fetchOwner; + } + + public boolean includeUserMetadata() { + return includeUserMetadata; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link ListObjectsV2Args}. */ + public static final class Builder extends BucketArgs.Builder { + public Builder delimiter(String delimiter) { + operations.add(args -> args.delimiter = delimiter); + return this; + } + + public Builder encodingType(String encodingType) { + operations.add(args -> args.encodingType = encodingType); + return this; + } + + public Builder maxKeys(Integer maxKeys) { + if (maxKeys != null && maxKeys < 1) { + throw new IllegalArgumentException("valid max keys must be provided"); + } + + operations.add(args -> args.maxKeys = maxKeys); + return this; + } + + public Builder prefix(String prefix) { + operations.add(args -> args.prefix = prefix); + return this; + } + + public Builder startAfter(String startAfter) { + operations.add(args -> args.startAfter = startAfter); + return this; + } + + public Builder continuationToken(String continuationToken) { + operations.add(args -> args.continuationToken = continuationToken); + return this; + } + + public Builder fetchOwner(boolean fetchOwner) { + operations.add(args -> args.fetchOwner = fetchOwner); + return this; + } + + public Builder includeUserMetadata(boolean includeUserMetadata) { + operations.add(args -> args.includeUserMetadata = includeUserMetadata); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListObjectsV2Args)) return false; + if (!super.equals(o)) return false; + ListObjectsV2Args that = (ListObjectsV2Args) o; + return Objects.equals(delimiter, that.delimiter) + && Objects.equals(encodingType, that.encodingType) + && Objects.equals(maxKeys, that.maxKeys) + && Objects.equals(prefix, that.prefix) + && Objects.equals(startAfter, that.startAfter) + && Objects.equals(continuationToken, that.continuationToken) + && fetchOwner == that.fetchOwner + && includeUserMetadata == that.includeUserMetadata; + } + + @Override + public int hashCode() { + return Objects.hash( + super.hashCode(), + delimiter, + encodingType, + maxKeys, + prefix, + startAfter, + continuationToken, + fetchOwner, + includeUserMetadata); + } +} diff --git a/api/src/main/java/io/minio/ListObjectsV2Response.java b/api/src/main/java/io/minio/ListObjectsV2Response.java index 4a0ca0f47..01f50f86a 100644 --- a/api/src/main/java/io/minio/ListObjectsV2Response.java +++ b/api/src/main/java/io/minio/ListObjectsV2Response.java @@ -19,7 +19,7 @@ import io.minio.messages.ListBucketResultV2; import okhttp3.Headers; -/** Response class of {@link S3Base#listObjectsV2Async}. */ +/** Response of {@link BaseS3Client#listObjectsV2}. */ public class ListObjectsV2Response extends GenericResponse { private ListBucketResultV2 result; diff --git a/api/src/main/java/io/minio/ListPartsArgs.java b/api/src/main/java/io/minio/ListPartsArgs.java new file mode 100644 index 000000000..dff97394d --- /dev/null +++ b/api/src/main/java/io/minio/ListPartsArgs.java @@ -0,0 +1,84 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#listParts}. */ +public class ListPartsArgs extends ObjectArgs { + private String uploadId; + private Integer maxParts; + private Integer partNumberMarker; + + public String uploadId() { + return uploadId; + } + + public Integer maxParts() { + return maxParts; + } + + public Integer partNumberMarker() { + return partNumberMarker; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link ListPartsArgs}. */ + public static final class Builder extends BucketArgs.Builder { + public Builder uploadId(String uploadId) { + Utils.validateNotEmptyString(uploadId, "upload ID"); + operations.add(args -> args.uploadId = uploadId); + return this; + } + + public Builder maxParts(Integer maxParts) { + if (maxParts != null && maxParts < 1) { + throw new IllegalArgumentException("valid max parts must be provided"); + } + + operations.add(args -> args.maxParts = maxParts); + return this; + } + + public Builder partNumberMarker(Integer partNumberMarker) { + if (partNumberMarker != null && (partNumberMarker < 1 || partNumberMarker > 10000)) { + throw new IllegalArgumentException("valid part number marker must be provided"); + } + operations.add(args -> args.partNumberMarker = partNumberMarker); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListPartsArgs)) return false; + if (!super.equals(o)) return false; + ListPartsArgs that = (ListPartsArgs) o; + return Objects.equals(uploadId, that.uploadId) + && Objects.equals(maxParts, that.maxParts) + && Objects.equals(partNumberMarker, that.partNumberMarker); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), uploadId, maxParts, partNumberMarker); + } +} diff --git a/api/src/main/java/io/minio/ListPartsResponse.java b/api/src/main/java/io/minio/ListPartsResponse.java index 8b45dfea5..165619ba3 100644 --- a/api/src/main/java/io/minio/ListPartsResponse.java +++ b/api/src/main/java/io/minio/ListPartsResponse.java @@ -19,7 +19,7 @@ import io.minio.messages.ListPartsResult; import okhttp3.Headers; -/** Response class of {@link S3Base#listPartsAsync}. */ +/** Response of {@link BaseS3Client#listParts}. */ public class ListPartsResponse extends GenericResponse { private ListPartsResult result; diff --git a/api/src/main/java/io/minio/ListenBucketNotificationArgs.java b/api/src/main/java/io/minio/ListenBucketNotificationArgs.java index a1dc359bc..a56e86a3f 100644 --- a/api/src/main/java/io/minio/ListenBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/ListenBucketNotificationArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#listenBucketNotification} and {@link + * Arguments of {@link MinioAsyncClient#listenBucketNotification} and {@link * MinioClient#listenBucketNotification}. */ public class ListenBucketNotificationArgs extends BucketArgs { @@ -44,11 +44,11 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link ListenBucketNotificationArgs}. */ + /** Builder of {@link ListenBucketNotificationArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateEvents(String[] events) { - validateNotNull(events, "events"); + Utils.validateNotNull(events, "events"); } protected void validate(ListenBucketNotificationArgs args) { @@ -89,6 +89,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), prefix, suffix, events); + return Objects.hash(super.hashCode(), prefix, suffix, Arrays.hashCode(events)); } } diff --git a/api/src/main/java/io/minio/MakeBucketArgs.java b/api/src/main/java/io/minio/MakeBucketArgs.java index 81b9e0ac3..b96478b24 100644 --- a/api/src/main/java/io/minio/MakeBucketArgs.java +++ b/api/src/main/java/io/minio/MakeBucketArgs.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,39 +16,12 @@ package io.minio; -import java.util.Objects; - -/** Argument class of {@link MinioAsyncClient#makeBucket} and {@link MinioClient#makeBucket}. */ -public class MakeBucketArgs extends BucketArgs { - private boolean objectLock; - - public boolean objectLock() { - return objectLock; - } - +/** Arguments of {@link MinioAsyncClient#makeBucket} and {@link MinioClient#makeBucket}. */ +public class MakeBucketArgs extends CreateBucketBaseArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link MakeBucketArgs}. */ - public static final class Builder extends BucketArgs.Builder { - public Builder objectLock(boolean objectLock) { - operations.add(args -> args.objectLock = objectLock); - return this; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof MakeBucketArgs)) return false; - if (!super.equals(o)) return false; - MakeBucketArgs that = (MakeBucketArgs) o; - return objectLock == that.objectLock; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), objectLock); - } + /** Builder of {@link MakeBucketArgs}. */ + public static final class Builder extends CreateBucketBaseArgs.Builder {} } diff --git a/api/src/main/java/io/minio/MinioAsyncClient.java b/api/src/main/java/io/minio/MinioAsyncClient.java index f72e52622..ea6d50796 100644 --- a/api/src/main/java/io/minio/MinioAsyncClient.java +++ b/api/src/main/java/io/minio/MinioAsyncClient.java @@ -18,9 +18,13 @@ package io.minio; import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; import com.google.common.io.ByteStreams; import io.minio.credentials.Credentials; import io.minio.credentials.Provider; @@ -28,24 +32,21 @@ import io.minio.errors.BucketPolicyTooLargeException; 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.MinioException; import io.minio.errors.XmlParserException; -import io.minio.http.HttpUtils; -import io.minio.http.Method; import io.minio.messages.AccessControlPolicy; -import io.minio.messages.Bucket; import io.minio.messages.CORSConfiguration; -import io.minio.messages.CopyObjectResult; -import io.minio.messages.CreateBucketConfiguration; -import io.minio.messages.DeleteError; -import io.minio.messages.DeleteObject; +import io.minio.messages.DeleteRequest; +import io.minio.messages.DeleteResult; import io.minio.messages.GetObjectAttributesOutput; import io.minio.messages.Item; import io.minio.messages.LegalHold; import io.minio.messages.LifecycleConfiguration; import io.minio.messages.ListAllMyBucketsResult; +import io.minio.messages.ListBucketResultV1; +import io.minio.messages.ListBucketResultV2; +import io.minio.messages.ListObjectsResult; +import io.minio.messages.ListVersionsResult; import io.minio.messages.NotificationConfiguration; import io.minio.messages.NotificationRecords; import io.minio.messages.ObjectLockConfiguration; @@ -60,6 +61,7 @@ import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.math.BigInteger; @@ -70,10 +72,10 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -81,14 +83,23 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; -import java.util.regex.Matcher; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; import okhttp3.HttpUrl; +import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.Response; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; @@ -139,27 +150,101 @@ * .build(); * } */ -public class MinioAsyncClient extends S3Base { +public class MinioAsyncClient extends BaseS3Client { + /** Argument builder of {@link MinioAsyncClient}. */ + public static final class Builder { + private Http.BaseUrl baseUrl = null; + private String region; + private Provider provider; + private OkHttpClient httpClient; + private boolean closeHttpClient; + + public Builder baseUrl(Http.BaseUrl baseUrl) { + if (baseUrl.region() == null) { + baseUrl.setRegion(region); + } + region = null; + this.baseUrl = baseUrl; + return this; + } + + public Builder endpoint(String endpoint) { + return this.baseUrl(new Http.BaseUrl(endpoint)); + } + + public Builder endpoint(String endpoint, int port, boolean secure) { + return this.baseUrl(new Http.BaseUrl(endpoint, port, secure)); + } + + public Builder endpoint(URL url) { + return this.baseUrl(new Http.BaseUrl(url)); + } + + public Builder endpoint(HttpUrl url) { + return this.baseUrl(new Http.BaseUrl(url)); + } + + public Builder region(String region) { + if (region != null && !Utils.REGION_REGEX.matcher(region).find()) { + throw new IllegalArgumentException("invalid region " + region); + } + if (baseUrl != null) { + baseUrl.setRegion(region); + } else { + this.region = region; + } + return this; + } + + public Builder credentials(String accessKey, String secretKey) { + provider = new StaticProvider(accessKey, secretKey, null); + return this; + } + + public Builder credentialsProvider(Provider provider) { + this.provider = provider; + return this; + } + + public Builder httpClient(OkHttpClient httpClient) { + Utils.validateNotNull(httpClient, "http client"); + this.httpClient = httpClient; + return this; + } + + public Builder httpClient(OkHttpClient httpClient, boolean close) { + Utils.validateNotNull(httpClient, "http client"); + this.httpClient = httpClient; + this.closeHttpClient = close; + return this; + } + + public MinioAsyncClient build() { + Utils.validateNotNull(baseUrl, "endpoint"); + + if (baseUrl.awsDomainSuffix() != null + && baseUrl.awsDomainSuffix().endsWith(".cn") + && !baseUrl.awsS3Prefix().endsWith("s3-accelerate.") + && baseUrl.region() == null) { + throw new IllegalArgumentException("Region missing in Amazon S3 China endpoint " + baseUrl); + } + + if (httpClient == null) { + closeHttpClient = true; + httpClient = Http.newDefaultClient(); + } + + return new MinioAsyncClient(baseUrl, provider, httpClient, closeHttpClient); + } + } + + public static Builder builder() { + return new Builder(); + } + private MinioAsyncClient( - HttpUrl baseUrl, - String awsS3Prefix, - String awsDomainSuffix, - boolean awsDualstack, - boolean useVirtualStyle, - String region, - Provider provider, - OkHttpClient httpClient, - boolean closeHttpClient) { - super( - baseUrl, - awsS3Prefix, - awsDomainSuffix, - awsDualstack, - useVirtualStyle, - region, - provider, - httpClient, - closeHttpClient); + Http.BaseUrl baseUrl, Provider provider, OkHttpClient httpClient, boolean closeHttpClient) { + super(baseUrl, provider, httpClient, closeHttpClient); } protected MinioAsyncClient(MinioAsyncClient client) { @@ -206,18 +291,13 @@ protected MinioAsyncClient(MinioAsyncClient client) { * * @param args {@link StatObjectArgs} object. * @return {@link CompletableFuture}<{@link StatObjectResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. * @see StatObjectResponse */ public CompletableFuture statObject(StatObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return super.statObjectAsync(args); + throws MinioException { + return headObject(new HeadObjectArgs(args)) + .thenApply(response -> new StatObjectResponse(response)); } /** @@ -236,23 +316,18 @@ public CompletableFuture statObject(StatObjectArgs args) * * @param args Object of {@link GetObjectArgs} * @return {@link CompletableFuture}<{@link GetObjectResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. * @see GetObjectResponse */ - public CompletableFuture getObject(GetObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture getObject(GetObjectArgs args) throws MinioException { checkArgs(args); - args.validateSsec(this.baseUrl); + args.validateSsec(this.baseUrl.isHttps()); return executeGetAsync( args, - args.getHeaders(), - (args.versionId() != null) ? newMultimap("versionId", args.versionId()) : null) + args.makeHeaders(), + (args.versionId() != null) + ? new Http.QueryParameters("versionId", args.versionId()) + : null) .thenApply( response -> { return new GetObjectResponse( @@ -267,23 +342,23 @@ public CompletableFuture getObject(GetObjectArgs args) private void downloadObject( String filename, boolean overwrite, - StatObjectResponse statObjectResponse, + HeadObjectResponse headObjectResponse, GetObjectResponse getObjectResponse) - throws IOException { + throws MinioException { OutputStream os = null; try { Path filePath = Paths.get(filename); String tempFilename = - filename + "." + S3Escaper.encode(statObjectResponse.etag()) + ".part.minio"; + filename + "." + Utils.encode(headObjectResponse.etag()) + ".part.minio"; Path tempFilePath = Paths.get(tempFilename); if (Files.exists(tempFilePath)) Files.delete(tempFilePath); os = Files.newOutputStream(tempFilePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE); long bytesWritten = ByteStreams.copy(getObjectResponse, os); - if (bytesWritten != statObjectResponse.size()) { + if (bytesWritten != headObjectResponse.size()) { throw new IOException( tempFilename + ": unexpected data written. expected = " - + statObjectResponse.size() + + headObjectResponse.size() + ", written = " + bytesWritten); } @@ -293,9 +368,15 @@ private void downloadObject( } else { Files.move(tempFilePath, filePath); } + } catch (IOException e) { + throw new MinioException(e); } finally { - getObjectResponse.close(); - if (os != null) os.close(); + try { + getObjectResponse.close(); + if (os != null) os.close(); + } catch (IOException e) { + throw new MinioException(e); + } } } @@ -314,30 +395,23 @@ private void downloadObject( * * @param args Object of {@link DownloadObjectArgs} * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture downloadObject(DownloadObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture downloadObject(DownloadObjectArgs args) throws MinioException { String filename = args.filename(); Path filePath = Paths.get(filename); if (!args.overwrite() && Files.exists(filePath)) { throw new IllegalArgumentException("Destination file " + filename + " already exists"); } - return statObjectAsync(new StatObjectArgs(args)) + return headObject(new HeadObjectArgs(args)) .thenCombine( getObject(new GetObjectArgs(args)), - (statObjectResponse, getObjectResponse) -> { + (headObjectResponse, getObjectResponse) -> { try { - downloadObject(filename, args.overwrite(), statObjectResponse, getObjectResponse); + downloadObject(filename, args.overwrite(), headObjectResponse, getObjectResponse); return null; - } catch (IOException e) { + } catch (MinioException e) { throw new CompletionException(e); } }) @@ -355,7 +429,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-objectname") * .build()) @@ -368,7 +442,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-source-objectname") * .build()) @@ -381,7 +455,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-objectname") * .build()) @@ -395,7 +469,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-objectname") * .build()) @@ -409,7 +483,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-objectname") * .build()) @@ -423,7 +497,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-source-objectname") * .ssec(ssec) // Replace with actual key. @@ -437,7 +511,7 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * .bucket("my-bucketname") * .object("my-objectname") * .source( - * CopySource.builder() + * SourceObject.builder() * .bucket("my-source-bucketname") * .object("my-objectname") * .matchETag(etag) // Replace with actual etag. @@ -448,133 +522,239 @@ public CompletableFuture downloadObject(DownloadObjectArgs args) * * @param args {@link CopyObjectArgs} object. * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture copyObject(CopyObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - args.validateSse(this.baseUrl); + args.validateSse(this.baseUrl.isHttps()); - return CompletableFuture.supplyAsync( - () -> args.source().offset() != null && args.source().length() != null) + CompletableFuture future = + args.source().objectSize() == null + ? headObject(new HeadObjectArgs(args.source())) + : CompletableFuture.completedFuture((HeadObjectResponse) null); + return future + .thenApply( + response -> + response == null + ? args + : new CopyObjectArgs( + args, new SourceObject(args.source(), response.size(), response.etag()))) .thenCompose( - condition -> { - if (condition) { - try { - return statObjectAsync(new StatObjectArgs((ObjectReadArgs) args.source())); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); + copyArgs -> { + long size = copyArgs.source().objectSize(); + try { + if (size < ObjectWriteArgs.MAX_PART_SIZE + && copyArgs.source().offset() == null + && copyArgs.source().length() == null) { + return super.copyObject(copyArgs); } - } - return CompletableFuture.completedFuture(null); - }) - .thenApply(stat -> (stat == null) ? (long) -1 : stat.size()) - .thenCompose( - size -> { - if (args.source().offset() != null - || args.source().length() != null - || size > ObjectWriteArgs.MAX_PART_SIZE) { - if (args.metadataDirective() != null - && args.metadataDirective() == Directive.COPY) { - throw new IllegalArgumentException( - "COPY metadata directive is not applicable to source object size greater than" - + " 5 GiB"); + + if (size > ObjectWriteArgs.MAX_PART_SIZE) { + if (copyArgs.metadataDirective() == Directive.COPY) { + throw new IllegalArgumentException( + "COPY metadata directive is not applicable to source object size greater" + + " than 5 GiB"); + } } - if (args.taggingDirective() != null && args.taggingDirective() == Directive.COPY) { + if (copyArgs.taggingDirective() == Directive.COPY) { throw new IllegalArgumentException( "COPY tagging directive is not applicable to source object size greater than" + " 5 GiB"); } - try { - return composeObject(new ComposeObjectArgs(args)); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - } - return CompletableFuture.completedFuture(null); - }) - .thenCompose( - objectWriteResponse -> { - if (objectWriteResponse != null) { - return CompletableFuture.completedFuture(objectWriteResponse); + return composeObject(new ComposeObjectArgs(copyArgs)); + } catch (MinioException e) { + throw new CompletionException(e); } + }); + } - Multimap headers = args.genHeaders(); + protected CompletableFuture calculatePartCount(List sources) + throws MinioException { + long[] objectSize = {0}; + + CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> 0); + + int sourceSize = sources.size(); + for (int i = 0; i < sourceSize; i++) { + final int index = i; + final boolean interimPart = sourceSize != 1 && sourceSize != (i + 1); + + CompletableFuture future = + sources.get(index).objectSize() == null + ? headObject(new HeadObjectArgs(sources.get(index))) + : CompletableFuture.completedFuture((HeadObjectResponse) null); + completableFuture = + completableFuture.thenCombine( + future, + (partCount, response) -> { + SourceObject source = sources.get(index); + if (response != null) { + source = new SourceObject(source, response.size(), response.etag()); + sources.set(index, source); + } - if (args.metadataDirective() != null) { - headers.put("x-amz-metadata-directive", args.metadataDirective().name()); - } + long size = source.length() != null ? source.length() : source.objectSize(); + size -= source.offset() != null ? source.offset() : 0; + if (size < ObjectWriteArgs.MIN_MULTIPART_SIZE && interimPart) { + throw new IllegalArgumentException( + "compose source " + + source.bucket() + + "/" + + source.object() + + ": size " + + size + + " must be greater than " + + ObjectWriteArgs.MIN_MULTIPART_SIZE); + } - if (args.taggingDirective() != null) { - headers.put("x-amz-tagging-directive", args.taggingDirective().name()); - } + objectSize[0] += size; + if (objectSize[0] > ObjectWriteArgs.MAX_OBJECT_SIZE) { + throw new IllegalArgumentException( + "destination object size must be less than " + + ObjectWriteArgs.MAX_OBJECT_SIZE); + } - headers.putAll(args.source().genCopyHeaders()); + if (size > ObjectWriteArgs.MAX_PART_SIZE) { + long count = size / ObjectWriteArgs.MAX_PART_SIZE; + long lastPartSize = size - (count * ObjectWriteArgs.MAX_PART_SIZE); + if (lastPartSize > 0) { + count++; + } else { + lastPartSize = ObjectWriteArgs.MAX_PART_SIZE; + } + + if (lastPartSize < ObjectWriteArgs.MIN_MULTIPART_SIZE && interimPart) { + throw new IllegalArgumentException( + "compose source " + + source.bucket() + + "/" + + source.object() + + ": " + + "for multipart split upload of " + + size + + ", last part size is less than " + + ObjectWriteArgs.MIN_MULTIPART_SIZE); + } + partCount += (int) count; + } else { + partCount++; + } + + if (partCount > ObjectWriteArgs.MAX_MULTIPART_COUNT) { + throw new IllegalArgumentException( + "Compose sources create more than allowed multipart count " + + ObjectWriteArgs.MAX_MULTIPART_COUNT); + } + return partCount; + }); + } + + return completableFuture; + } + + private CompletableFuture uploadParts( + ComposeObjectArgs args, int partCount, String uploadId) throws MinioException { + Http.Headers ssecHeaders = + (args.sse() != null && args.sse() instanceof ServerSideEncryption.CustomerKey) + ? args.sse().headers() + : null; + + int partNumber = 0; + CompletableFuture future = CompletableFuture.supplyAsync(() -> new Part[partCount]); + for (SourceObject source : args.sources()) { + long size = source.objectSize(); + if (source.length() != null) { + size = source.length(); + } else if (source.offset() != null) { + size -= source.offset(); + } + long offset = source.offset() == null ? 0 : source.offset(); + final Http.Headers headers = Http.Headers.merge(source.headers(), ssecHeaders); + + if (size <= ObjectWriteArgs.MAX_PART_SIZE) { + partNumber++; + if (source.length() != null) { + headers.put( + Http.Headers.X_AMZ_COPY_SOURCE_RANGE, + "bytes=" + offset + "-" + (offset + source.length() - 1)); + } else if (source.offset() != null) { + headers.put( + Http.Headers.X_AMZ_COPY_SOURCE_RANGE, "bytes=" + offset + "-" + (offset + size - 1)); + } + + final int finalPartNumber = partNumber; + future = + future.thenCombine( + uploadPartCopy(new UploadPartCopyArgs(args, uploadId, finalPartNumber, headers)), + (parts, response) -> { + parts[response.partNumber() - 1] = response.part(); + return parts; + }); + continue; + } + + while (size > 0) { + partNumber++; + + long length = Math.min(size, ObjectWriteArgs.MAX_PART_SIZE); + long endBytes = offset + length - 1; + + Http.Headers finalHeaders = + new Http.Headers( + Http.Headers.X_AMZ_COPY_SOURCE_RANGE, "bytes=" + offset + "-" + endBytes); + finalHeaders.putAll(headers); + + final int finalPartNumber = partNumber; + future = + future.thenCombine( + uploadPartCopy(new UploadPartCopyArgs(args, uploadId, finalPartNumber, headers)), + (parts, response) -> { + parts[response.partNumber() - 1] = response.part(); + return parts; + }); + offset += length; + size -= length; + } + } + + return future; + } + + private CompletableFuture composeObject( + ComposeObjectArgs args, int partCount) throws MinioException { + String[] uploadId = {null}; + return createMultipartUpload(new CreateMultipartUploadArgs(args)) + .thenCompose( + response -> { + uploadId[0] = response.result().uploadId(); try { - return executePutAsync(args, headers, null, null, 0) - .thenApply( - response -> { - try { - CopyObjectResult result = - Xml.unmarshal(CopyObjectResult.class, response.body().charStream()); - return new ObjectWriteResponse( - response.headers(), - args.bucket(), - args.region(), - args.object(), - result.etag(), - response.header("x-amz-version-id"), - result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { + return uploadParts(args, partCount, uploadId[0]); + } catch (MinioException e) { throw new CompletionException(e); } - }); - } - - private CompletableFuture uploadPartCopy( - String bucketName, - String region, - String objectName, - String uploadId, - int partNumber, - Multimap headers, - Part[] parts) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return uploadPartCopyAsync(bucketName, region, objectName, uploadId, partNumber, headers, null) - .thenApply( - uploadPartCopyResponse -> { - parts[partNumber - 1] = new Part(partNumber, uploadPartCopyResponse.result().etag()); - return parts; + }) + .thenCompose( + parts -> { + try { + return completeMultipartUpload( + new CompleteMultipartUploadArgs(args, uploadId[0], parts)); + } catch (MinioException e) { + throw new CompletionException(e); + } + }) + .exceptionally( + e -> { + if (uploadId[0] != null) { + try { + abortMultipartUpload(new AbortMultipartUploadArgs(args, uploadId[0])).get(); + } catch (MinioException | InterruptedException | ExecutionException ex) { + e.addSuppressed(ex); + } + } + throw new CompletionException(e); }); } @@ -582,14 +762,14 @@ private CompletableFuture uploadPartCopy( * Creates an object by combining data from different source objects using server-side copy. * *
Example:{@code
-   * List sourceObjectList = new ArrayList();
+   * List sourceObjectList = new ArrayList();
    *
    * sourceObjectList.add(
-   *    ComposeSource.builder().bucket("my-job-bucket").object("my-objectname-part-one").build());
+   *    SourceObject.builder().bucket("my-job-bucket").object("my-objectname-part-one").build());
    * sourceObjectList.add(
-   *    ComposeSource.builder().bucket("my-job-bucket").object("my-objectname-part-two").build());
+   *    SourceObject.builder().bucket("my-job-bucket").object("my-objectname-part-two").build());
    * sourceObjectList.add(
-   *    ComposeSource.builder().bucket("my-job-bucket").object("my-objectname-part-three").build());
+   *    SourceObject.builder().bucket("my-job-bucket").object("my-objectname-part-three").build());
    *
    * // Create my-bucketname/my-objectname by combining source object list.
    * CompletableFuture future = minioAsyncClient.composeObject(
@@ -625,246 +805,26 @@ private CompletableFuture uploadPartCopy(
    *
    * @param args {@link ComposeObjectArgs} object.
    * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object.
-   * @throws InsufficientDataException thrown to indicate not enough data available in InputStream.
-   * @throws InternalException thrown to indicate internal library error.
-   * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library.
-   * @throws IOException thrown to indicate I/O error on S3 operation.
-   * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
-   * @throws XmlParserException thrown to indicate XML parsing error.
+   * @throws MinioException thrown to indicate SDK exception.
    */
   public CompletableFuture composeObject(ComposeObjectArgs args)
-      throws InsufficientDataException, InternalException, InvalidKeyException, IOException,
-          NoSuchAlgorithmException, XmlParserException {
+      throws MinioException {
     checkArgs(args);
-    args.validateSse(this.baseUrl);
-    List sources = args.sources();
-    int[] partCount = {0};
-    String[] uploadIdCopy = {null};
+    args.validateSse(this.baseUrl.isHttps());
 
-    return calculatePartCountAsync(sources)
-        .thenApply(
-            count -> {
-              partCount[0] = count;
-              return (count == 1
-                  && args.sources().get(0).offset() == null
-                  && args.sources().get(0).length() == null);
-            })
+    return calculatePartCount(args.sources())
         .thenCompose(
-            copyObjectFlag -> {
-              if (copyObjectFlag) {
-                try {
+            partCount -> {
+              try {
+                if (partCount == 1
+                    && args.sources().get(0).offset() == null
+                    && args.sources().get(0).length() == null) {
                   return copyObject(new CopyObjectArgs(args));
-                } catch (InsufficientDataException
-                    | InternalException
-                    | InvalidKeyException
-                    | IOException
-                    | NoSuchAlgorithmException
-                    | XmlParserException e) {
-                  throw new CompletionException(e);
                 }
+                return composeObject(args, partCount);
+              } catch (MinioException e) {
+                throw new CompletionException(e);
               }
-              return CompletableFuture.completedFuture(null);
-            })
-        .thenCompose(
-            objectWriteResponse -> {
-              if (objectWriteResponse != null) {
-                return CompletableFuture.completedFuture(objectWriteResponse);
-              }
-
-              CompletableFuture completableFuture =
-                  CompletableFuture.supplyAsync(
-                          () -> {
-                            Multimap headers = newMultimap(args.extraHeaders());
-                            headers.putAll(args.genHeaders());
-                            return headers;
-                          })
-                      .thenCompose(
-                          headers -> {
-                            try {
-                              return createMultipartUploadAsync(
-                                  args.bucket(),
-                                  args.region(),
-                                  args.object(),
-                                  headers,
-                                  args.extraQueryParams());
-                            } catch (InsufficientDataException
-                                | InternalException
-                                | InvalidKeyException
-                                | IOException
-                                | NoSuchAlgorithmException
-                                | XmlParserException e) {
-                              throw new CompletionException(e);
-                            }
-                          })
-                      .thenApply(
-                          createMultipartUploadResponse -> {
-                            String uploadId = createMultipartUploadResponse.result().uploadId();
-                            uploadIdCopy[0] = uploadId;
-                            return uploadId;
-                          })
-                      .thenCompose(
-                          uploadId -> {
-                            Multimap ssecHeaders = HashMultimap.create();
-                            if (args.sse() != null
-                                && args.sse() instanceof ServerSideEncryptionCustomerKey) {
-                              ssecHeaders.putAll(newMultimap(args.sse().headers()));
-                            }
-
-                            int partNumber = 0;
-                            CompletableFuture future =
-                                CompletableFuture.supplyAsync(
-                                    () -> {
-                                      return new Part[partCount[0]];
-                                    });
-                            for (ComposeSource src : sources) {
-                              long size = 0;
-                              try {
-                                size = src.objectSize();
-                              } catch (InternalException e) {
-                                throw new CompletionException(e);
-                              }
-                              if (src.length() != null) {
-                                size = src.length();
-                              } else if (src.offset() != null) {
-                                size -= src.offset();
-                              }
-                              long offset = 0;
-                              if (src.offset() != null) offset = src.offset();
-
-                              final Multimap headers;
-                              try {
-                                headers = newMultimap(src.headers());
-                              } catch (InternalException e) {
-                                throw new CompletionException(e);
-                              }
-                              headers.putAll(ssecHeaders);
-
-                              if (size <= ObjectWriteArgs.MAX_PART_SIZE) {
-                                partNumber++;
-                                if (src.length() != null) {
-                                  headers.put(
-                                      "x-amz-copy-source-range",
-                                      "bytes=" + offset + "-" + (offset + src.length() - 1));
-                                } else if (src.offset() != null) {
-                                  headers.put(
-                                      "x-amz-copy-source-range",
-                                      "bytes=" + offset + "-" + (offset + size - 1));
-                                }
-
-                                final int partNum = partNumber;
-                                future =
-                                    future.thenCompose(
-                                        parts -> {
-                                          try {
-                                            return uploadPartCopy(
-                                                args.bucket(),
-                                                args.region(),
-                                                args.object(),
-                                                uploadId,
-                                                partNum,
-                                                headers,
-                                                parts);
-                                          } catch (InsufficientDataException
-                                              | InternalException
-                                              | InvalidKeyException
-                                              | IOException
-                                              | NoSuchAlgorithmException
-                                              | XmlParserException e) {
-                                            throw new CompletionException(e);
-                                          }
-                                        });
-                                continue;
-                              }
-
-                              while (size > 0) {
-                                partNumber++;
-
-                                long length = size;
-                                if (length > ObjectWriteArgs.MAX_PART_SIZE) {
-                                  length = ObjectWriteArgs.MAX_PART_SIZE;
-                                }
-                                long endBytes = offset + length - 1;
-
-                                Multimap headersCopy = newMultimap(headers);
-                                headersCopy.put(
-                                    "x-amz-copy-source-range", "bytes=" + offset + "-" + endBytes);
-
-                                final int partNum = partNumber;
-                                future =
-                                    future.thenCompose(
-                                        parts -> {
-                                          try {
-                                            return uploadPartCopy(
-                                                args.bucket(),
-                                                args.region(),
-                                                args.object(),
-                                                uploadId,
-                                                partNum,
-                                                headersCopy,
-                                                parts);
-                                          } catch (InsufficientDataException
-                                              | InternalException
-                                              | InvalidKeyException
-                                              | IOException
-                                              | NoSuchAlgorithmException
-                                              | XmlParserException e) {
-                                            throw new CompletionException(e);
-                                          }
-                                        });
-                                offset += length;
-                                size -= length;
-                              }
-                            }
-
-                            return future;
-                          })
-                      .thenCompose(
-                          parts -> {
-                            try {
-                              return completeMultipartUploadAsync(
-                                  args.bucket(),
-                                  args.region(),
-                                  args.object(),
-                                  uploadIdCopy[0],
-                                  parts,
-                                  null,
-                                  null);
-                            } catch (InsufficientDataException
-                                | InternalException
-                                | InvalidKeyException
-                                | IOException
-                                | NoSuchAlgorithmException
-                                | XmlParserException e) {
-                              throw new CompletionException(e);
-                            }
-                          });
-
-              completableFuture.exceptionally(
-                  e -> {
-                    if (uploadIdCopy[0] != null) {
-                      try {
-                        abortMultipartUploadAsync(
-                                args.bucket(),
-                                args.region(),
-                                args.object(),
-                                uploadIdCopy[0],
-                                null,
-                                null)
-                            .get();
-                      } catch (InsufficientDataException
-                          | InternalException
-                          | InvalidKeyException
-                          | IOException
-                          | NoSuchAlgorithmException
-                          | XmlParserException
-                          | InterruptedException
-                          | ExecutionException ex) {
-                        throw new CompletionException(ex);
-                      }
-                    }
-                    throw new CompletionException(e);
-                  });
-              return completableFuture;
             });
   }
 
@@ -877,7 +837,7 @@ public CompletableFuture composeObject(ComposeObjectArgs ar
    * String url =
    *    minioAsyncClient.getPresignedObjectUrl(
    *        GetPresignedObjectUrlArgs.builder()
-   *            .method(Method.DELETE)
+   *            .method(Http.Method.DELETE)
    *            .bucket("my-bucketname")
    *            .object("my-objectname")
    *            .expiry(24 * 60 * 60)
@@ -892,7 +852,7 @@ public CompletableFuture composeObject(ComposeObjectArgs ar
    * String url =
    *    minioAsyncClient.getPresignedObjectUrl(
    *        GetPresignedObjectUrlArgs.builder()
-   *            .method(Method.PUT)
+   *            .method(Http.Method.PUT)
    *            .bucket("my-bucketname")
    *            .object("my-objectname")
    *            .expiry(1, TimeUnit.DAYS)
@@ -905,7 +865,7 @@ public CompletableFuture composeObject(ComposeObjectArgs ar
    * String url =
    *    minioAsyncClient.getPresignedObjectUrl(
    *        GetPresignedObjectUrlArgs.builder()
-   *            .method(Method.GET)
+   *            .method(Http.Method.GET)
    *            .bucket("my-bucketname")
    *            .object("my-objectname")
    *            .expiry(2, TimeUnit.HOURS)
@@ -915,56 +875,38 @@ public CompletableFuture composeObject(ComposeObjectArgs ar
    *
    * @param args {@link GetPresignedObjectUrlArgs} object.
    * @return String - URL string.
-   * @throws ErrorResponseException thrown to indicate S3 service returned an error response.
-   * @throws InsufficientDataException thrown to indicate not enough data available in InputStream.
-   * @throws InternalException thrown to indicate internal library error.
-   * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library.
-   * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error
-   *     response.
-   * @throws IOException thrown to indicate I/O error on S3 operation.
-   * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
-   * @throws XmlParserException thrown to indicate XML parsing error.
-   * @throws ServerException
+   * @throws MinioException thrown to indicate SDK exception.
    */
-  public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args)
-      throws ErrorResponseException, InsufficientDataException, InternalException,
-          InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
-          XmlParserException, ServerException {
+  public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) throws MinioException {
     checkArgs(args);
 
-    byte[] body =
-        (args.method() == Method.PUT || args.method() == Method.POST) ? HttpUtils.EMPTY_BODY : null;
-
-    Multimap queryParams = newMultimap(args.extraQueryParams());
-    if (args.versionId() != null) queryParams.put("versionId", args.versionId());
-
     String region = null;
     try {
-      region = getRegionAsync(args.bucket(), args.region()).get();
+      region = getRegion(args.bucket(), args.region()).get();
     } catch (InterruptedException e) {
       throw new RuntimeException(e);
     } catch (ExecutionException e) {
       throwEncapsulatedException(e);
     }
 
-    if (provider == null) {
-      HttpUrl url = buildUrl(args.method(), args.bucket(), args.object(), region, queryParams);
-      return url.toString();
+    Http.QueryParameters queryParams = new Http.QueryParameters();
+    if (args.versionId() == null) queryParams.put("versionId", args.versionId());
+
+    Credentials credentials = provider == null ? null : provider.fetch();
+    if (credentials != null && credentials.sessionToken() != null) {
+      queryParams.put(Http.Headers.X_AMZ_SECURITY_TOKEN, credentials.sessionToken());
     }
 
-    Credentials creds = provider.fetch();
-    if (creds.sessionToken() != null) queryParams.put("X-Amz-Security-Token", creds.sessionToken());
-    HttpUrl url = buildUrl(args.method(), args.bucket(), args.object(), region, queryParams);
-    Request request =
-        createRequest(
-            url,
-            args.method(),
-            args.extraHeaders() == null ? null : httpHeaders(args.extraHeaders()),
-            body,
-            0,
-            creds);
-    url = Signer.presignV4(request, region, creds.accessKey(), creds.secretKey(), args.expiry());
-    return url.toString();
+    return Http.S3Request.builder()
+        .userAgent(userAgent)
+        .method(args.method())
+        .args(args)
+        .queryParams(queryParams)
+        .build()
+        .toPresignedRequest(baseUrl, region, credentials, args.expiry())
+        .httpRequest()
+        .url()
+        .toString();
   }
 
   /**
@@ -1014,21 +956,10 @@ public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args)
    *
    * @param policy Post policy of an object.
    * @return {@code Map} - Contains form-data to upload an object using POST method.
-   * @throws ErrorResponseException thrown to indicate S3 service returned an error response.
-   * @throws InsufficientDataException thrown to indicate not enough data available in InputStream.
-   * @throws InternalException thrown to indicate internal library error.
-   * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library.
-   * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error
-   *     response.
-   * @throws IOException thrown to indicate I/O error on S3 operation.
-   * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
-   * @throws XmlParserException thrown to indicate XML parsing error.
+   * @throws MinioException thrown to indicate SDK exception.
    * @see PostPolicy
    */
-  public Map getPresignedPostFormData(PostPolicy policy)
-      throws ErrorResponseException, InsufficientDataException, InternalException,
-          InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
-          ServerException, XmlParserException {
+  public Map getPresignedPostFormData(PostPolicy policy) throws MinioException {
     if (provider == null) {
       throw new IllegalArgumentException(
           "Anonymous access does not require presigned post form-data");
@@ -1036,7 +967,7 @@ public Map getPresignedPostFormData(PostPolicy policy)
 
     String region = null;
     try {
-      region = getRegionAsync(policy.bucket(), null).get();
+      region = getRegion(policy.bucket(), null).get();
     } catch (InterruptedException e) {
       throw new RuntimeException(e);
     } catch (ExecutionException e) {
@@ -1073,26 +1004,18 @@ public Map getPresignedPostFormData(PostPolicy policy)
    *
    * @param args {@link RemoveObjectArgs} object.
    * @return {@link CompletableFuture}<{@link Void}> object.
-   * @throws ErrorResponseException thrown to indicate S3 service returned an error response.
-   * @throws InsufficientDataException thrown to indicate not enough data available in InputStream.
-   * @throws InternalException thrown to indicate internal library error.
-   * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library.
-   * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error
-   *     response.
-   * @throws IOException thrown to indicate I/O error on S3 operation.
-   * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
-   * @throws XmlParserException thrown to indicate XML parsing error.
+   * @throws MinioException thrown to indicate SDK exception.
    */
-  public CompletableFuture removeObject(RemoveObjectArgs args)
-      throws InsufficientDataException, InternalException, InvalidKeyException, IOException,
-          NoSuchAlgorithmException, XmlParserException {
+  public CompletableFuture removeObject(RemoveObjectArgs args) throws MinioException {
     checkArgs(args);
     return executeDeleteAsync(
             args,
             args.bypassGovernanceMode()
-                ? newMultimap("x-amz-bypass-governance-retention", "true")
+                ? new Http.Headers("x-amz-bypass-governance-retention", "true")
                 : null,
-            (args.versionId() != null) ? newMultimap("versionId", args.versionId()) : null)
+            (args.versionId() != null)
+                ? new Http.QueryParameters("versionId", args.versionId())
+                : null)
         .thenAccept(response -> response.close());
   }
 
@@ -1105,35 +1028,36 @@ public CompletableFuture removeObject(RemoveObjectArgs args)
    * objects.add(new DeleteObject("my-objectname1"));
    * objects.add(new DeleteObject("my-objectname2"));
    * objects.add(new DeleteObject("my-objectname3"));
-   * Iterable> results =
+   * Iterable> results =
    *     minioAsyncClient.removeObjects(
    *         RemoveObjectsArgs.builder().bucket("my-bucketname").objects(objects).build());
-   * for (Result result : results) {
-   *   DeleteError error = result.get();
+   * for (Result result : results) {
+   *   DeleteResult.Error error = result.get();
    *   System.out.println(
    *       "Error in deleting object " + error.objectName() + "; " + error.message());
    * }
    * }
* * @param args {@link RemoveObjectsArgs} object. - * @return {@code Iterable>} - Lazy iterator contains object removal status. + * @return {@code Iterable>} - Lazy iterator contains object removal + * status. */ - public Iterable> removeObjects(RemoveObjectsArgs args) { + public Iterable> removeObjects(RemoveObjectsArgs args) { checkArgs(args); - return new Iterable>() { + return new Iterable>() { @Override - public Iterator> iterator() { - return new Iterator>() { - private Result error = null; - private Iterator errorIterator = null; + public Iterator> iterator() { + return new Iterator>() { + private Result error = null; + private Iterator errorIterator = null; private boolean completed = false; - private Iterator objectIter = args.objects().iterator(); + private Iterator objectIter = args.objects().iterator(); private void setError() { error = null; while (errorIterator.hasNext()) { - DeleteError deleteError = errorIterator.next(); + DeleteResult.Error deleteError = errorIterator.next(); if (!"NoSuchVersion".equals(deleteError.code())) { error = new Result<>(deleteError); break; @@ -1147,7 +1071,7 @@ private synchronized void populate() { } try { - List objectList = new LinkedList<>(); + List objectList = new LinkedList<>(); while (objectIter.hasNext() && objectList.size() < 1000) { objectList.add(objectIter.next()); } @@ -1157,34 +1081,28 @@ private synchronized void populate() { DeleteObjectsResponse response = null; try { response = - deleteObjectsAsync( - args.bucket(), - args.region(), - objectList, - true, - args.bypassGovernanceMode(), - args.extraHeaders(), - args.extraQueryParams()) + deleteObjects( + DeleteObjectsArgs.builder() + .extraHeaders(args.extraHeaders()) + .extraQueryParams(args.extraQueryParams()) + .bucket(args.bucket()) + .region(args.region()) + .objects(objectList) + .quiet(true) + .bypassGovernanceMode(args.bypassGovernanceMode()) + .build()) .get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { throwEncapsulatedException(e); } - if (!response.result().errorList().isEmpty()) { - errorIterator = response.result().errorList().iterator(); + if (!response.result().errors().isEmpty()) { + errorIterator = response.result().errors().iterator(); setError(); completed = true; } - } catch (ErrorResponseException - | InsufficientDataException - | InternalException - | InvalidKeyException - | InvalidResponseException - | IOException - | NoSuchAlgorithmException - | ServerException - | XmlParserException e) { + } catch (MinioException e) { error = new Result<>(e); completed = true; } @@ -1205,11 +1123,11 @@ public boolean hasNext() { } @Override - public Result next() { + public Result next() { if (!hasNext()) throw new NoSuchElementException(); if (this.error != null) { - Result error = this.error; + Result error = this.error; this.error = null; return error; } @@ -1251,18 +1169,15 @@ public void remove() { * * @param args {@link RestoreObjectArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture restoreObject(RestoreObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture restoreObject(RestoreObjectArgs args) throws MinioException { checkArgs(args); - return executePostAsync(args, null, newMultimap("restore", ""), args.request()) + return executePostAsync( + args, + null, + new Http.QueryParameters("restore", ""), + new Http.Body(args.request(), null, null, null)) .thenAccept(response -> response.close()); } @@ -1307,39 +1222,33 @@ public CompletableFuture restoreObject(RestoreObjectArgs args) * * @param args Instance of {@link ListObjectsArgs} built using the builder * @return {@code Iterable>} - Lazy iterator contains object information. - * @throws XmlParserException upon parsing response xml */ public Iterable> listObjects(ListObjectsArgs args) { if (args.includeVersions() || args.versionIdMarker() != null) { - return listObjectVersions(args); + return objectVersionLister(new ListObjectVersionsArgs(args)); } if (args.useApiVersion1()) { - return listObjectsV1(args); + return objectV1Lister(new ListObjectsV1Args(args)); } - return listObjectsV2(args); + return objectV2Lister(new ListObjectsV2Args(args)); } /** * Lists bucket information of all buckets. * *
Example:{@code
-   * CompletableFuture> future = minioAsyncClient.listBuckets();
+   * CompletableFuture> future = minioAsyncClient.listBuckets();
    * }
* - * @return {@link CompletableFuture}<{@link List}<{@link Bucket}>> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @return {@link CompletableFuture}<{@link List}<{@link + * ListAllMyBucketsResult.Bucket}>> object. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture> listBuckets() - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return listBucketsAsync(null, null, null, null, null, null) + public CompletableFuture> listBuckets() + throws MinioException { + return listBucketsAPI(ListBucketsArgs.builder().build()) .thenApply( response -> { return response.result().buckets(); @@ -1350,41 +1259,45 @@ public CompletableFuture> listBuckets() * Lists bucket information of all buckets. * *
Example:{@code
-   * Iterable> results = minioAsyncClient.listBuckets(ListBucketsArgs.builder().build());
-   * for (Result result : results) {
+   * Iterable> results = minioAsyncClient.listBuckets(ListBucketsArgs.builder().build());
+   * for (Result result : results) {
    *   Bucket bucket = result.get();
    *   System.out.println(String.format("Bucket: %s, Region: %s, CreationDate: %s", bucket.name(), bucket.bucketRegion(), bucket.creationDate()));
    * }
    * }
* - * @return {@link Iterable}<{@link List}<{@link Bucket}>> object. + * @return {@link Iterable}<{@link List}<{@link ListAllMyBucketsResult.Bucket}>> + * object. */ - public Iterable> listBuckets(ListBucketsArgs args) { - return new Iterable>() { + public Iterable> listBuckets(ListBucketsArgs args) { + return new Iterable>() { @Override - public Iterator> iterator() { - return new Iterator>() { + public Iterator> iterator() { + return new Iterator>() { private ListAllMyBucketsResult result = null; - private Result error = null; - private Iterator iterator = null; + private Result error = null; + private Iterator iterator = null; private boolean completed = false; private synchronized void populate() { if (completed) return; try { - this.iterator = new LinkedList().iterator(); + this.iterator = Collections.emptyIterator(); try { ListBucketsResponse response = - listBucketsAsync( - args.bucketRegion(), - args.maxBuckets(), - args.prefix(), - (result == null) - ? args.continuationToken() - : result.continuationToken(), - args.extraHeaders(), - args.extraQueryParams()) + listBucketsAPI( + ListBucketsArgs.builder() + .extraHeaders(args.extraHeaders()) + .extraQueryParams(args.extraQueryParams()) + .bucketRegion(args.bucketRegion()) + .maxBuckets(args.maxBuckets()) + .prefix(args.prefix()) + .continuationToken( + result == null + ? args.continuationToken() + : result.continuationToken()) + .build()) .get(); this.result = response.result(); } catch (InterruptedException e) { @@ -1393,15 +1306,7 @@ private synchronized void populate() { throwEncapsulatedException(e); } this.iterator = this.result.buckets().iterator(); - } catch (ErrorResponseException - | InsufficientDataException - | InternalException - | InvalidKeyException - | InvalidResponseException - | IOException - | NoSuchAlgorithmException - | ServerException - | XmlParserException e) { + } catch (MinioException e) { this.error = new Result<>(e); completed = true; } @@ -1430,7 +1335,7 @@ public boolean hasNext() { } @Override - public Result next() { + public Result next() { if (this.completed) throw new NoSuchElementException(); if (this.error == null && this.iterator == null) { populate(); @@ -1448,7 +1353,7 @@ public Result next() { return this.error; } - Bucket item = null; + ListAllMyBucketsResult.Bucket item = null; if (this.iterator.hasNext()) { item = this.iterator.next(); } @@ -1480,16 +1385,9 @@ public void remove() { * * @param args {@link BucketExistsArgs} object. * @return {@link CompletableFuture}<{@link Boolean}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture bucketExists(BucketExistsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture bucketExists(BucketExistsArgs args) throws MinioException { return executeHeadAsync(args, null, null) .exceptionally( e -> { @@ -1547,52 +1445,12 @@ public CompletableFuture bucketExists(BucketExistsArgs args) * } * * @param args Object with bucket name, region and lock functionality - * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @return {@link CompletableFuture}<{@link GenericResponse}> object. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture makeBucket(MakeBucketArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture makeBucket(MakeBucketArgs args) throws MinioException { checkArgs(args); - - String region = args.region(); - if (this.region != null && !this.region.isEmpty()) { - // Error out if region does not match with region passed via constructor. - if (region != null && !region.equals(this.region)) { - throw new IllegalArgumentException( - "region must be " + this.region + ", but passed " + region); - } - - region = this.region; - } - - if (region == null) { - region = US_EAST_1; - } - - Multimap headers = - args.objectLock() ? newMultimap("x-amz-bucket-object-lock-enabled", "true") : null; - final String location = region; - - return executeAsync( - Method.PUT, - args.bucket(), - null, - location, - httpHeaders(merge(args.extraHeaders(), headers)), - args.extraQueryParams(), - location.equals(US_EAST_1) ? null : new CreateBucketConfiguration(location), - 0) - .thenAccept( - response -> { - regionCache.put(args.bucket(), location); - response.close(); - }); + return createBucket(new CreateBucketArgs(args)); } /** @@ -1605,18 +1463,16 @@ public CompletableFuture makeBucket(MakeBucketArgs args) * * @param args {@link SetBucketVersioningArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setBucketVersioning(SetBucketVersioningArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("versioning", ""), args.config(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("versioning", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -1631,19 +1487,12 @@ public CompletableFuture setBucketVersioning(SetBucketVersioningArgs args) * * @param args {@link GetBucketVersioningArgs} object. * @return {@link CompletableFuture}<{@link VersioningConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getBucketVersioning( - GetBucketVersioningArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + GetBucketVersioningArgs args) throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("versioning", "")) + return executeGetAsync(args, null, new Http.QueryParameters("versioning", "")) .thenApply( response -> { try { @@ -1668,18 +1517,16 @@ public CompletableFuture getBucketVersioning( * * @param args {@link SetObjectLockConfigurationArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setObjectLockConfiguration(SetObjectLockConfigurationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("object-lock", ""), args.config(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("object-lock", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -1693,20 +1540,16 @@ public CompletableFuture setObjectLockConfiguration(SetObjectLockConfigura * * @param args {@link DeleteObjectLockConfigurationArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture deleteObjectLockConfiguration( - DeleteObjectLockConfigurationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + DeleteObjectLockConfigurationArgs args) throws MinioException { checkArgs(args); return executePutAsync( - args, null, newMultimap("object-lock", ""), new ObjectLockConfiguration(), 0) + args, + null, + new Http.QueryParameters("object-lock", ""), + new Http.Body(new ObjectLockConfiguration(), null, null, null)) .thenAccept(response -> response.close()); } @@ -1721,19 +1564,12 @@ args, null, newMultimap("object-lock", ""), new ObjectLockConfiguration(), 0) * * @param args {@link GetObjectLockConfigurationArgs} object. * @return {@link CompletableFuture}<{@link ObjectLockConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getObjectLockConfiguration( - GetObjectLockConfigurationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + GetObjectLockConfigurationArgs args) throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("object-lock", "")) + return executeGetAsync(args, null, new Http.QueryParameters("object-lock", "")) .thenApply( response -> { try { @@ -1763,27 +1599,20 @@ public CompletableFuture getObjectLockConfiguration( * * @param args {@link SetObjectRetentionArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setObjectRetention(SetObjectRetentionArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("retention", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("retention", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executePutAsync( args, args.bypassGovernanceMode() - ? newMultimap("x-amz-bypass-governance-retention", "True") + ? new Http.Headers("x-amz-bypass-governance-retention", "True") : null, queryParams, - args.config(), - 0) + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -1801,18 +1630,12 @@ public CompletableFuture setObjectRetention(SetObjectRetentionArgs args) * * @param args {@link GetObjectRetentionArgs} object. * @return {@link CompletableFuture}<{@link Retention}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getObjectRetention(GetObjectRetentionArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("retention", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("retention", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .exceptionally( @@ -1864,20 +1687,15 @@ public CompletableFuture getObjectRetention(GetObjectRetentionArgs ar * * @param args {@link EnableObjectLegalHoldArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture enableObjectLegalHold(EnableObjectLegalHoldArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("legal-hold", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("legal-hold", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); - return executePutAsync(args, null, queryParams, new LegalHold(true), 0) + return executePutAsync( + args, null, queryParams, new Http.Body(new LegalHold(true), null, null, null)) .thenAccept(response -> response.close()); } @@ -1895,20 +1713,15 @@ public CompletableFuture enableObjectLegalHold(EnableObjectLegalHoldArgs a * * @param args {@link DisableObjectLegalHoldArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture disableObjectLegalHold(DisableObjectLegalHoldArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("legal-hold", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("legal-hold", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); - return executePutAsync(args, null, queryParams, new LegalHold(false), 0) + return executePutAsync( + args, null, queryParams, new Http.Body(new LegalHold(false), null, null, null)) .thenAccept(response -> response.close()); } @@ -1927,18 +1740,12 @@ public CompletableFuture disableObjectLegalHold(DisableObjectLegalHoldArgs * * @param args {@link IsObjectLegalHoldEnabledArgs} object. * @return {@link CompletableFuture}<{@link Boolean}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("legal-hold", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("legal-hold", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .exceptionally( @@ -1987,21 +1794,356 @@ public CompletableFuture isObjectLegalHoldEnabled(IsObjectLegalHoldEnab * * @param args {@link RemoveBucketArgs} bucket. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture removeBucket(RemoveBucketArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture removeBucket(RemoveBucketArgs args) throws MinioException { checkArgs(args); return executeDeleteAsync(args, null, null) .thenAccept(response -> regionCache.remove(args.bucket())); } + private CompletableFuture> uploadPartsSequentially( + PutObjectBaseArgs args, + String uploadId, + PartReader partReader, + boolean computeSha256, + boolean sha256Algorithm, + ByteBuffer buffer, + long partSize, + List responses) { + return CompletableFuture.supplyAsync( + () -> + new UploadPartArgs( + args, + uploadId, + partReader.partNumber(), + buffer, + Checksum.makeHeaders(partReader.hashers(), computeSha256, sha256Algorithm))) + .thenCompose( + partArgs -> { + try { + return uploadPart(partArgs); + } catch (MinioException e) { + return Utils.failedFuture(e); + } + }) + .thenCompose( + response -> { + responses.add(response); + try { + buffer.reset(); + if (partReader.partNumber() == partReader.partCount()) { + return CompletableFuture.completedFuture(responses); + } + partReader.read(buffer); + } catch (MinioException e) { + return Utils.failedFuture(e); + } + return uploadPartsSequentially( + args, + uploadId, + partReader, + computeSha256, + sha256Algorithm, + buffer, + partSize, + responses); + }); + } + + public static class ByteArrayPool { + private final BlockingQueue pool; + long bufferSize; + + public ByteArrayPool(int capacity, long bufferSize) { + this.pool = new ArrayBlockingQueue<>(capacity); + this.bufferSize = bufferSize; + // Optionally pre-fill + for (int i = 0; i < capacity - 1; i++) { + if (!pool.offer(new ByteBuffer(bufferSize))) { + throw new RuntimeException("unable to allocate byte buffer; this should not happen"); + } + } + } + + public ByteBuffer borrow() { + ByteBuffer buffer = pool.poll(); // non-blocking + return (buffer != null) ? buffer : new ByteBuffer(bufferSize); + } + + public void release(ByteBuffer buffer) { + try { + buffer.reset(); + if (!pool.offer(buffer)) return; // ignore if pool is full + } catch (MinioException e) { + throw new RuntimeException(e); + } + } + } + + public static class UploadPartArgsWrapper { + final UploadPartArgs args; + + UploadPartArgsWrapper(UploadPartArgs args) { + this.args = args; + } + + public UploadPartArgs args() { + return args; + } + } + + private CompletableFuture> uploadPartsParallelly( + PutObjectBaseArgs args, + String uploadId, + PartReader partReader, + boolean computeSha256, + boolean sha256Algorithm, + ByteBuffer buffer, + long partSize, + int parallelUploads) { + ByteArrayPool bytePool = new ByteArrayPool(parallelUploads, partSize); + ExecutorService uploadExecutor = Executors.newFixedThreadPool(parallelUploads); + BlockingQueue queue = new ArrayBlockingQueue<>(parallelUploads); + CountDownLatch doneLatch = new CountDownLatch(parallelUploads); + List uploadResults = Collections.synchronizedList(new ArrayList<>()); + AtomicBoolean errorOccurred = new AtomicBoolean(false); + ConcurrentLinkedQueue exceptions = new ConcurrentLinkedQueue<>(); + + return CompletableFuture.supplyAsync( + () -> { + try { + // Start uploader workers + for (int i = 0; i < parallelUploads; i++) { + Future result = + uploadExecutor.submit( + () -> { + try { + while (!errorOccurred.get()) { + UploadPartArgsWrapper part = queue.take(); + if (part.args() == null) break; // poison pill + UploadPartResponse response = uploadPart(part.args()).join(); + bytePool.release(part.args().buffer()); + uploadResults.add(response); + } + } catch (InterruptedException | MinioException e) { + errorOccurred.set(true); // signal to all threads + exceptions.add(e); + } finally { + doneLatch.countDown(); + } + }); + if (result == null) { + throw new RuntimeException( + "uploadExecutor.submit() returns null; this should not happen"); + } + } + + // Reader: submit initial buffer + queue.put( + new UploadPartArgsWrapper( + new UploadPartArgs( + args, + uploadId, + partReader.partNumber(), + buffer, + Checksum.makeHeaders( + partReader.hashers(), computeSha256, sha256Algorithm)))); + + // Reader: loop to submit remaining parts + while (partReader.partNumber() != partReader.partCount() && !errorOccurred.get()) { + ByteBuffer buf = bytePool.borrow(); + partReader.read(buf); + queue.put( + new UploadPartArgsWrapper( + new UploadPartArgs( + args, + uploadId, + partReader.partNumber(), + buf, + Checksum.makeHeaders( + partReader.hashers(), computeSha256, sha256Algorithm)))); + } + + // Signal all workers to stop with poison pills + for (int i = 0; i < parallelUploads; i++) { + queue.put(new UploadPartArgsWrapper(null)); + } + + doneLatch.await(); + uploadExecutor.shutdown(); + + if (!exceptions.isEmpty()) { + CompletionException combined = + new CompletionException("uploadPartsParallelly failed", exceptions.peek()); + exceptions.stream().skip(1).forEach(combined::addSuppressed); + throw combined; + } + + uploadResults.sort(Comparator.comparingInt(r -> r.part().partNumber())); + return uploadResults; + + } catch (InterruptedException | MinioException e) { + throw new CompletionException(e); + } finally { + uploadExecutor.shutdownNow(); // ensure executor exits on error + } + }); + } + + private CompletableFuture putObject( + PutObjectBaseArgs args, Object fileStreamData, MediaType contentType, boolean computeSha256) + throws MinioException { + RandomAccessFile file = null; + InputStream stream = null; + byte[] data = null; + if (fileStreamData instanceof RandomAccessFile) file = (RandomAccessFile) fileStreamData; + if (fileStreamData instanceof InputStream) stream = (InputStream) fileStreamData; + if (fileStreamData instanceof byte[]) data = (byte[]) fileStreamData; + + Checksum.Algorithm algorithm = args.checksum(); + if (algorithm == null) algorithm = Checksum.Algorithm.CRC32C; + boolean sha256Algorithm = algorithm == Checksum.Algorithm.SHA256; + + List algorithmList = new ArrayList<>(); + algorithmList.add(algorithm); + if (computeSha256 && !sha256Algorithm) algorithmList.add(Checksum.Algorithm.SHA256); + Checksum.Algorithm[] algorithms = algorithmList.toArray(new Checksum.Algorithm[0]); + + PartReader partReader = null; + ByteBuffer buffer = null; + int partCount = args.partCount(); + + if (stream != null) { + partReader = + new PartReader(stream, args.objectSize(), args.partSize(), args.partCount(), algorithms); + buffer = new ByteBuffer(partReader.partCount() == 1 ? args.objectSize() : args.partSize()); + partReader.read(buffer); + partCount = partReader.partCount(); + } + + if (partCount == 1) { + if (stream != null) { + return putObject( + new PutObjectAPIArgs( + args, + buffer, + contentType, + Checksum.makeHeaders(partReader.hashers(), computeSha256, sha256Algorithm))); + } + + if (args.objectSize() == null) { + throw new MinioException("object size is null; this should not happen"); + } + long length = args.objectSize(); + + Map hashers = Checksum.newHasherMap(algorithms); + + if (file != null) { + try { + long position = file.getFilePointer(); + Checksum.update(hashers, file, length); + file.seek(position); + } catch (IOException e) { + throw new MinioException(e); + } + return putObject( + new PutObjectAPIArgs( + args, + file, + length, + contentType, + Checksum.makeHeaders(hashers, computeSha256, sha256Algorithm))); + } + + Checksum.update(hashers, data, (int) length); + return putObject( + new PutObjectAPIArgs( + args, + data, + (int) length, + contentType, + Checksum.makeHeaders(hashers, computeSha256, sha256Algorithm))); + } + + // Multipart upload starts here + + if (args.checksum() != null && !args.checksum().compositeSupport()) { + throw new IllegalArgumentException( + "unsupported checksum " + args.checksum() + " for multipart upload"); + } + + if (file != null) { + partReader = + new PartReader(file, args.objectSize(), args.partSize(), args.partCount(), algorithms); + buffer = new ByteBuffer(args.partSize()); + partReader.read(buffer); + } + + int parallelUploads = args.parallelUploads(); + if (parallelUploads <= 0) parallelUploads = 1; + if (partReader.partCount() > 0 && parallelUploads > partReader.partCount()) { + parallelUploads = partReader.partCount(); + } + + String[] uploadId = {null}; + final PartReader finalPartReader = partReader; + final ByteBuffer finalBuffer = buffer; + final int finalParallelUploads = parallelUploads; + return createMultipartUpload(new CreateMultipartUploadArgs(args, contentType, algorithm)) + .thenCompose( + response -> { + uploadId[0] = response.result().uploadId(); + // Do sequential multipart uploads + if (finalParallelUploads == 1) { + return uploadPartsSequentially( + args, + uploadId[0], + finalPartReader, + computeSha256, + sha256Algorithm, + finalBuffer, + args.partSize(), + new ArrayList()); + } + + // Do sequential multipart uploads + return uploadPartsParallelly( + args, + uploadId[0], + finalPartReader, + computeSha256, + sha256Algorithm, + finalBuffer, + args.partSize(), + finalParallelUploads); + }) + .thenCompose( + responses -> { + try { + return completeMultipartUpload( + new CompleteMultipartUploadArgs( + args, + uploadId[0], + responses.stream() + .map(UploadPartResponse::part) + .toArray(io.minio.messages.Part[]::new))); + } catch (MinioException e) { + return Utils.failedFuture(e); + } + }) + .exceptionally( + e -> { + try { + abortMultipartUpload(new AbortMultipartUploadArgs(args, uploadId[0])); + } catch (MinioException ex) { + Logger.getLogger(this.getClass().getSimpleName()) + .warning("AbortMultipartUpload REST API failed; " + ex); + } + throw new CompletionException(e); + }); + } + /** * Uploads data from a stream to an object. * @@ -2048,25 +2190,21 @@ public CompletableFuture removeBucket(RemoveBucketArgs args) * * @param args {@link PutObjectArgs} object. * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture putObject(PutObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - args.validateSse(this.baseUrl); - return putObjectAsync( - args, - args.stream(), - args.objectSize(), - args.partSize(), - args.partCount(), - args.contentType()); + args.validateSse(this.baseUrl.isHttps()); + try { + return putObject( + args, + args.stream() != null ? args.stream() : args.data(), + args.contentType(), + !this.baseUrl.isHttps()); + } catch (IOException e) { + throw new MinioException(e); + } } /** @@ -2090,50 +2228,47 @@ public CompletableFuture putObject(PutObjectArgs args) * * @param args {@link UploadObjectArgs} object. * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture uploadObject(UploadObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - args.validateSse(this.baseUrl); - final RandomAccessFile file = new RandomAccessFile(args.filename(), "r"); - return putObjectAsync( - args, file, args.objectSize(), args.partSize(), args.partCount(), args.contentType()) - .exceptionally( - e -> { - try { - file.close(); - } catch (IOException ex) { - throw new CompletionException(ex); - } + args.validateSse(this.baseUrl.isHttps()); + try { + final RandomAccessFile file = new RandomAccessFile(args.filename(), "r"); + return putObject(args, file, args.contentType(), !this.baseUrl.isHttps()) + .exceptionally( + e -> { + try { + file.close(); + } catch (IOException ex) { + throw new CompletionException(new MinioException(ex)); + } - Throwable ex = e.getCause(); + Throwable ex = e.getCause(); - if (ex instanceof CompletionException) { - ex = ((CompletionException) ex).getCause(); - } + if (ex instanceof CompletionException) { + ex = ((CompletionException) ex).getCause(); + } - if (ex instanceof ExecutionException) { - ex = ((ExecutionException) ex).getCause(); - } + if (ex instanceof ExecutionException) { + ex = ((ExecutionException) ex).getCause(); + } - throw new CompletionException(ex); - }) - .thenApply( - objectWriteResponse -> { - try { - file.close(); - } catch (IOException e) { - throw new CompletionException(e); - } - return objectWriteResponse; - }); + throw new CompletionException(ex); + }) + .thenApply( + objectWriteResponse -> { + try { + file.close(); + } catch (IOException e) { + throw new CompletionException(new MinioException(e)); + } + return objectWriteResponse; + }); + } catch (IOException e) { + throw new MinioException(e); + } } /** @@ -2147,18 +2282,11 @@ public CompletableFuture uploadObject(UploadObjectArgs args * * @param args {@link GetBucketPolicyArgs} object. * @return {@link CompletableFuture}<{@link String}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture getBucketPolicy(GetBucketPolicyArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture getBucketPolicy(GetBucketPolicyArgs args) throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("policy", "")) + return executeGetAsync(args, null, new Http.QueryParameters("policy", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2212,7 +2340,7 @@ public CompletableFuture getBucketPolicy(GetBucketPolicyArgs args) return new String(buf, 0, bytesRead, StandardCharsets.UTF_8); } catch (IOException e) { - throw new CompletionException(e); + throw new CompletionException(new MinioException(e)); } finally { response.close(); } @@ -2251,23 +2379,15 @@ public CompletableFuture getBucketPolicy(GetBucketPolicyArgs args) * * @param args {@link SetBucketPolicyArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture setBucketPolicy(SetBucketPolicyArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture setBucketPolicy(SetBucketPolicyArgs args) throws MinioException { checkArgs(args); return executePutAsync( args, - newMultimap("Content-Type", "application/json"), - newMultimap("policy", ""), - args.config(), - 0) + null, + new Http.QueryParameters("policy", ""), + new Http.Body(args.config(), Http.JSON_MEDIA_TYPE, null, null)) .thenAccept(response -> response.close()); } @@ -2282,18 +2402,12 @@ public CompletableFuture setBucketPolicy(SetBucketPolicyArgs args) * * @param args {@link DeleteBucketPolicyArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture deleteBucketPolicy(DeleteBucketPolicyArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("policy", "")) + return executeDeleteAsync(args, null, new Http.QueryParameters("policy", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2344,18 +2458,16 @@ public CompletableFuture deleteBucketPolicy(DeleteBucketPolicyArgs args) * * @param args {@link SetBucketLifecycleArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setBucketLifecycle(SetBucketLifecycleArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("lifecycle", ""), args.config(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("lifecycle", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -2369,18 +2481,12 @@ public CompletableFuture setBucketLifecycle(SetBucketLifecycleArgs args) * * @param args {@link DeleteBucketLifecycleArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture deleteBucketLifecycle(DeleteBucketLifecycleArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("lifecycle", "")) + return executeDeleteAsync(args, null, new Http.QueryParameters("lifecycle", "")) .thenAccept(response -> response.close()); } @@ -2396,18 +2502,12 @@ public CompletableFuture deleteBucketLifecycle(DeleteBucketLifecycleArgs a * @param args {@link GetBucketLifecycleArgs} object. * @return {@link LifecycleConfiguration} object. * @return {@link CompletableFuture}<{@link LifecycleConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getBucketLifecycle(GetBucketLifecycleArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("lifecycle", "")) + return executeGetAsync(args, null, new Http.QueryParameters("lifecycle", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2454,19 +2554,12 @@ public CompletableFuture getBucketLifecycle(GetBucketLif * * @param args {@link GetBucketNotificationArgs} object. * @return {@link CompletableFuture}<{@link NotificationConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getBucketNotification( - GetBucketNotificationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + GetBucketNotificationArgs args) throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("notification", "")) + return executeGetAsync(args, null, new Http.QueryParameters("notification", "")) .thenApply( response -> { try { @@ -2505,18 +2598,16 @@ public CompletableFuture getBucketNotification( * * @param args {@link SetBucketNotificationArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setBucketNotification(SetBucketNotificationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("notification", ""), args.config(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("notification", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -2530,19 +2621,16 @@ public CompletableFuture setBucketNotification(SetBucketNotificationArgs a * * @param args {@link DeleteBucketNotificationArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture deleteBucketNotification(DeleteBucketNotificationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); return executePutAsync( - args, null, newMultimap("notification", ""), new NotificationConfiguration(), 0) + args, + null, + new Http.QueryParameters("notification", ""), + new Http.Body(new NotificationConfiguration(null, null, null, null), null, null, null)) .thenAccept(response -> response.close()); } @@ -2557,19 +2645,12 @@ args, null, newMultimap("notification", ""), new NotificationConfiguration(), 0) * * @param args {@link GetBucketReplicationArgs} object. * @return {@link CompletableFuture}<{@link ReplicationConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getBucketReplication( - GetBucketReplicationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + GetBucketReplicationArgs args) throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("replication", "")) + return executeGetAsync(args, null, new Http.QueryParameters("replication", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2638,25 +2719,18 @@ public CompletableFuture getBucketReplication( * * @param args {@link SetBucketReplicationArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setBucketReplication(SetBucketReplicationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); return executePutAsync( args, (args.objectLockToken() != null) - ? newMultimap("x-amz-bucket-object-lock-token", args.objectLockToken()) + ? new Http.Headers("x-amz-bucket-object-lock-token", args.objectLockToken()) : null, - newMultimap("replication", ""), - args.config(), - 0) + new Http.QueryParameters("replication", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -2670,18 +2744,12 @@ public CompletableFuture setBucketReplication(SetBucketReplicationArgs arg * * @param args {@link DeleteBucketReplicationArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture deleteBucketReplication(DeleteBucketReplicationArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("replication", "")) + return executeDeleteAsync(args, null, new Http.QueryParameters("replication", "")) .thenAccept(response -> response.close()); } @@ -2714,25 +2782,14 @@ public CompletableFuture deleteBucketReplication(DeleteBucketReplicationAr * @param args {@link ListenBucketNotificationArgs} object. * @return {@code CloseableIterator>} - Lazy closable iterator * contains event records. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CloseableIterator> listenBucketNotification( - ListenBucketNotificationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + ListenBucketNotificationArgs args) throws MinioException { checkArgs(args); - Multimap queryParams = - newMultimap("prefix", args.prefix(), "suffix", args.suffix()); + Http.QueryParameters queryParams = + new Http.QueryParameters("prefix", args.prefix(), "suffix", args.suffix()); for (String event : args.events()) { queryParams.put("events", event); } @@ -2784,36 +2841,30 @@ public CloseableIterator> listenBucketNotification( * * @param args instance of {@link SelectObjectContentArgs} * @return {@link SelectResponseStream} - Contains filtered records and progress. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public SelectResponseStream selectObjectContent(SelectObjectContentArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { checkArgs(args); - args.validateSsec(this.baseUrl); + args.validateSsec(this.baseUrl.isHttps()); Response response = null; try { response = executePostAsync( args, - (args.ssec() != null) ? newMultimap(args.ssec().headers()) : null, - newMultimap("select", "", "select-type", "2"), - new SelectObjectContentRequest( - args.sqlExpression(), - args.requestProgress(), - args.inputSerialization(), - args.outputSerialization(), - args.scanStartRange(), - args.scanEndRange())) + args.ssec() == null ? null : args.ssec().headers(), + new Http.QueryParameters("select", "", "select-type", "2"), + new Http.Body( + new SelectObjectContentRequest( + args.sqlExpression(), + args.requestProgress(), + args.inputSerialization(), + args.outputSerialization(), + args.scanStartRange(), + args.scanEndRange()), + null, + null, + null)) .get(); } catch (InterruptedException e) { throw new RuntimeException(e); @@ -2833,18 +2884,16 @@ public SelectResponseStream selectObjectContent(SelectObjectContentArgs args) * * @param args {@link SetBucketEncryptionArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture setBucketEncryption(SetBucketEncryptionArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("encryption", ""), args.config(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("encryption", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -2859,18 +2908,12 @@ public CompletableFuture setBucketEncryption(SetBucketEncryptionArgs args) * * @param args {@link GetBucketEncryptionArgs} object. * @return {@link CompletableFuture}<{@link SseConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getBucketEncryption(GetBucketEncryptionArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("encryption", "")) + return executeGetAsync(args, null, new Http.QueryParameters("encryption", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2916,18 +2959,12 @@ public CompletableFuture getBucketEncryption(GetBucketEncrypti * * @param args {@link DeleteBucketEncryptionArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture deleteBucketEncryption(DeleteBucketEncryptionArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("encryption", "")) + return executeDeleteAsync(args, null, new Http.QueryParameters("encryption", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2966,18 +3003,11 @@ public CompletableFuture deleteBucketEncryption(DeleteBucketEncryptionArgs * * @param args {@link GetBucketTagsArgs} object. * @return {@link CompletableFuture}<{@link Tags}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture getBucketTags(GetBucketTagsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture getBucketTags(GetBucketTagsArgs args) throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("tagging", "")) + return executeGetAsync(args, null, new Http.QueryParameters("tagging", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -3023,18 +3053,15 @@ public CompletableFuture getBucketTags(GetBucketTagsArgs args) * * @param args {@link SetBucketTagsArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture setBucketTags(SetBucketTagsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture setBucketTags(SetBucketTagsArgs args) throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("tagging", ""), args.tags(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("tagging", ""), + new Http.Body(args.tags(), null, null, null)) .thenAccept(response -> response.close()); } @@ -3048,18 +3075,11 @@ public CompletableFuture setBucketTags(SetBucketTagsArgs args) * * @param args {@link DeleteBucketTagsArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture deleteBucketTags(DeleteBucketTagsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture deleteBucketTags(DeleteBucketTagsArgs args) throws MinioException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("tagging", "")) + return executeDeleteAsync(args, null, new Http.QueryParameters("tagging", "")) .thenAccept(response -> response.close()); } @@ -3074,18 +3094,11 @@ public CompletableFuture deleteBucketTags(DeleteBucketTagsArgs args) * * @param args {@link GetObjectTagsArgs} object. * @return {@link CompletableFuture}<{@link Tags}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture getObjectTags(GetObjectTagsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture getObjectTags(GetObjectTagsArgs args) throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("tagging", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("tagging", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .thenApply( @@ -3117,20 +3130,13 @@ public CompletableFuture getObjectTags(GetObjectTagsArgs args) * * @param args {@link SetObjectTagsArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture setObjectTags(SetObjectTagsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture setObjectTags(SetObjectTagsArgs args) throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("tagging", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("tagging", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); - return executePutAsync(args, null, queryParams, args.tags(), 0) + return executePutAsync(args, null, queryParams, new Http.Body(args.tags(), null, null, null)) .thenAccept(response -> response.close()); } @@ -3144,18 +3150,11 @@ public CompletableFuture setObjectTags(SetObjectTagsArgs args) * * @param args {@link DeleteObjectTagsArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture deleteObjectTags(DeleteObjectTagsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture deleteObjectTags(DeleteObjectTagsArgs args) throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("tagging", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("tagging", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeDeleteAsync(args, null, queryParams).thenAccept(response -> response.close()); } @@ -3170,18 +3169,12 @@ public CompletableFuture deleteObjectTags(DeleteObjectTagsArgs args) * * @param args {@link GetBucketCorsArgs} object. * @return {@link CompletableFuture}<{@link CORSConfiguration}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getBucketCors(GetBucketCorsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("cors", "")) + return executeGetAsync(args, null, new Http.QueryParameters("cors", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -3247,18 +3240,15 @@ public CompletableFuture getBucketCors(GetBucketCorsArgs args * * @param args {@link SetBucketCorsArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture setBucketCors(SetBucketCorsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture setBucketCors(SetBucketCorsArgs args) throws MinioException { checkArgs(args); - return executePutAsync(args, null, newMultimap("cors", ""), args.config(), 0) + return executePutAsync( + args, + null, + new Http.QueryParameters("cors", ""), + new Http.Body(args.config(), null, null, null)) .thenAccept(response -> response.close()); } @@ -3272,18 +3262,11 @@ public CompletableFuture setBucketCors(SetBucketCorsArgs args) * * @param args {@link DeleteBucketCorsArgs} object. * @return {@link CompletableFuture}<{@link Void}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ - public CompletableFuture deleteBucketCors(DeleteBucketCorsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + public CompletableFuture deleteBucketCors(DeleteBucketCorsArgs args) throws MinioException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("cors", "")) + return executeDeleteAsync(args, null, new Http.QueryParameters("cors", "")) .thenAccept(response -> response.close()); } @@ -3298,18 +3281,12 @@ public CompletableFuture deleteBucketCors(DeleteBucketCorsArgs args) * * @param args {@link GetObjectAclArgs} object. * @return {@link CompletableFuture}<{@link AccessControlPolicy}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getObjectAcl(GetObjectAclArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("acl", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("acl", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .thenApply( @@ -3342,23 +3319,16 @@ public CompletableFuture getObjectAcl(GetObjectAclArgs args * * @param args {@link GetObjectAttributesArgs} object. * @return {@link CompletableFuture}<{@link GetObjectAttributesResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture getObjectAttributes( - GetObjectAttributesArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + GetObjectAttributesArgs args) throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("attributes", ""); + Http.QueryParameters queryParams = new Http.QueryParameters("attributes", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); - Multimap headers = HashMultimap.create(); + Http.Headers headers = new Http.Headers(); if (args.maxParts() != null) headers.put("x-amz-max-parts", args.maxParts().toString()); if (args.partNumberMarker() != null) { headers.put("x-amz-part-number-marker", args.partNumberMarker().toString()); @@ -3417,17 +3387,10 @@ public CompletableFuture getObjectAttributes( * * @param args {@link UploadSnowballObjectsArgs} object. * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture uploadSnowballObjects( - UploadSnowballObjectsArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + UploadSnowballObjectsArgs args) throws MinioException { checkArgs(args); return CompletableFuture.supplyAsync( @@ -3475,7 +3438,7 @@ public CompletableFuture uploadSnowballObjects( } tarOutputStream.finish(); } catch (IOException e) { - throw new CompletionException(e); + throw new CompletionException(new MinioException(e)); } finally { try { if (tarOutputStream != null) tarOutputStream.flush(); @@ -3487,34 +3450,21 @@ public CompletableFuture uploadSnowballObjects( if (bos != null) bos.close(); if (fos != null) fos.close(); } catch (IOException e) { - throw new CompletionException(e); + throw new CompletionException(new MinioException(e)); } } return baos; }) .thenCompose( baos -> { - Multimap headers = newMultimap(args.extraHeaders()); - headers.putAll(args.genHeaders()); + Http.Headers headers = args.makeHeaders(); headers.put("X-Amz-Meta-Snowball-Auto-Extract", "true"); if (args.stagingFilename() == null) { byte[] data = baos.toByteArray(); try { - return putObjectAsync( - args.bucket(), - args.region(), - args.object(), - data, - data.length, - headers, - args.extraQueryParams()); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { + return putObject(new PutObjectAPIArgs(args, data, data.length, headers)); + } catch (MinioException e) { throw new CompletionException(e); } } @@ -3525,20 +3475,10 @@ public CompletableFuture uploadSnowballObjects( "tarball size " + length + " is more than maximum allowed 5TiB"); } try (RandomAccessFile file = new RandomAccessFile(args.stagingFilename(), "r")) { - return putObjectAsync( - args.bucket(), - args.region(), - args.object(), - file, - length, - headers, - args.extraQueryParams()); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { + return putObject(new PutObjectAPIArgs(args, file, length, headers)); + } catch (IOException e) { + throw new CompletionException(new MinioException(e)); + } catch (MinioException e) { throw new CompletionException(e); } }); @@ -3566,22 +3506,34 @@ public CompletableFuture uploadSnowballObjects( * * @param args {@link PutObjectFanOutArgs} object. * @return {@link CompletableFuture}<{@link PutObjectFanOutResponse}> object. - * @throws ErrorResponseException thrown to indicate presigned POST data failure. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture putObjectFanOut(PutObjectFanOutArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - args.validateSse(this.baseUrl); + args.validateSse(this.baseUrl.isHttps()); return CompletableFuture.supplyAsync( () -> { + byte[] buf16k = new byte[16384]; // 16KiB buffer for optimization. + ByteBuffer buffer = new ByteBuffer(args.size()); + long bytesWritten = 0; + while (bytesWritten != args.size()) { + try { + int length = args.stream().read(buf16k); + if (length < 0) { + throw new InsufficientDataException( + "insufficient data; expected=" + args.size() + ", got=" + bytesWritten); + } + buffer.write(buf16k, 0, length); + bytesWritten += length; + } catch (IOException e) { + throw new CompletionException(new MinioException(e)); + } catch (MinioException e) { + throw new CompletionException(e); + } + } + // Build POST object data String objectName = "pan-out-" @@ -3617,33 +3569,20 @@ public CompletableFuture putObjectFanOut(PutObjectFanOu multipartBuilder.addFormDataPart( "file", "fanout-content", - new HttpRequestBody(new PartSource(args.stream(), args.size()), null)); + new Http.RequestBody(buffer, Http.DEFAULT_MEDIA_TYPE)); return multipartBuilder.build(); } catch (JsonProcessingException e) { - throw new CompletionException(e); - } catch (ErrorResponseException - | InsufficientDataException - | InternalException - | InvalidKeyException - | InvalidResponseException - | IOException - | NoSuchAlgorithmException - | ServerException - | XmlParserException e) { + throw new CompletionException(new MinioException(e)); + } catch (MinioException e) { throw new CompletionException(e); } }) .thenCompose( body -> { try { - return executePostAsync(args, null, null, body); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { + return executePostAsync(args, null, null, new Http.Body(body)); + } catch (MinioException e) { throw new CompletionException(e); } }) @@ -3660,7 +3599,7 @@ public CompletableFuture putObjectFanOut(PutObjectFanOu return new PutObjectFanOutResponse( response.headers(), args.bucket(), args.region(), results); } catch (IOException e) { - throw new CompletionException(e); + throw new CompletionException(new MinioException(e)); } finally { response.close(); } @@ -3672,196 +3611,389 @@ public CompletableFuture putObjectFanOut(PutObjectFanOu * * @param args {@link PromptObjectArgs} object. * @return {@link CompletableFuture}<{@link PromptObjectResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CompletableFuture promptObject(PromptObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { + throws MinioException { checkArgs(args); - Multimap queryParams = newMultimap("lambdaArn", args.lambdaArn()); - Multimap headers = - merge(newMultimap(args.headers()), newMultimap("Content-Type", "application/json")); + Http.QueryParameters queryParams = new Http.QueryParameters("lambdaArn", args.lambdaArn()); + Http.Headers headers = + Http.Headers.merge( + new Http.Headers(args.headers()), + new Http.Headers(Http.Headers.CONTENT_TYPE, Http.JSON_MEDIA_TYPE.toString())); Map promptArgs = args.promptArgs(); if (promptArgs == null) promptArgs = new HashMap<>(); promptArgs.put("prompt", args.prompt()); - byte[] data = objectMapper.writeValueAsString(promptArgs).getBytes(StandardCharsets.UTF_8); - - return executePostAsync(args, headers, queryParams, data) - .thenApply( - response -> { - return new PromptObjectResponse( - response.headers(), - args.bucket(), - args.region(), - args.object(), - response.body().byteStream()); - }); + try { + byte[] data = objectMapper.writeValueAsString(promptArgs).getBytes(StandardCharsets.UTF_8); + return executePostAsync( + args, headers, queryParams, new Http.Body(data, data.length, null, null, null)) + .thenApply( + response -> { + return new PromptObjectResponse( + response.headers(), + args.bucket(), + args.region(), + args.object(), + response.body().byteStream()); + }); + } catch (JsonProcessingException e) { + throw new MinioException(e); + } } - public static Builder builder() { - return new Builder(); + ///////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////// Higher level ListObjects implementation /////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// + + /** Throws encapsulated exception wrapped by {@link ExecutionException}. */ + public void throwEncapsulatedException(ExecutionException e) throws MinioException { + if (e == null) return; + + Throwable ex = e.getCause(); + + if (ex instanceof CompletionException) ex = ((CompletionException) ex).getCause(); + if (ex instanceof ExecutionException) ex = ((ExecutionException) ex).getCause(); + try { + throw ex; + } catch (MinioException exc) { + throw exc; + } catch (Throwable exc) { + throw new RuntimeException(exc.getCause() == null ? exc : exc.getCause()); + } } - /** Argument builder of {@link MinioClient}. */ - public static final class Builder { - private HttpUrl baseUrl; - private String awsS3Prefix; - private String awsDomainSuffix; - private boolean awsDualstack; - private boolean useVirtualStyle; + private abstract class ObjectIterator implements Iterator> { + protected Result error; + protected Iterator itemIterator; + protected Iterator deleteMarkerIterator; + protected Iterator prefixIterator; + protected boolean completed = false; + protected ListObjectsResult listObjectsResult; + protected String lastObjectName; - private String region; - private Provider provider; - private OkHttpClient httpClient; - private boolean closeHttpClient; + protected abstract void populateResult() throws MinioException; + + protected synchronized void populate() { + try { + populateResult(); + } catch (MinioException e) { + this.error = new Result<>(e); + } + + if (this.listObjectsResult != null) { + this.itemIterator = this.listObjectsResult.contents().iterator(); + this.deleteMarkerIterator = this.listObjectsResult.deleteMarkers().iterator(); + this.prefixIterator = this.listObjectsResult.commonPrefixes().iterator(); + } else { + this.itemIterator = Collections.emptyIterator(); + this.deleteMarkerIterator = Collections.emptyIterator(); + this.prefixIterator = Collections.emptyIterator(); + } + } - private void setAwsInfo(String host, boolean https) { - this.awsS3Prefix = null; - this.awsDomainSuffix = null; - this.awsDualstack = false; + @Override + public boolean hasNext() { + if (this.completed) return false; - if (!HttpUtils.HOSTNAME_REGEX.matcher(host).find()) return; + if (this.error == null + && this.itemIterator == null + && this.deleteMarkerIterator == null + && this.prefixIterator == null) { + populate(); + } - if (HttpUtils.AWS_ELB_ENDPOINT_REGEX.matcher(host).find()) { - String[] tokens = host.split("\\.elb\\.amazonaws\\.com", 1)[0].split("\\."); - this.region = tokens[tokens.length - 1]; - return; + if (this.error == null + && !this.itemIterator.hasNext() + && !this.deleteMarkerIterator.hasNext() + && !this.prefixIterator.hasNext() + && this.listObjectsResult.isTruncated()) { + populate(); } - if (!HttpUtils.AWS_ENDPOINT_REGEX.matcher(host).find()) return; + if (this.error != null) return true; + if (this.itemIterator.hasNext()) return true; + if (this.deleteMarkerIterator.hasNext()) return true; + if (this.prefixIterator.hasNext()) return true; + + this.completed = true; + return false; + } - if (!HttpUtils.AWS_S3_ENDPOINT_REGEX.matcher(host).find()) { - throw new IllegalArgumentException("invalid Amazon AWS host " + host); + @Override + public Result next() { + if (this.completed) throw new NoSuchElementException(); + if (this.error == null + && this.itemIterator == null + && this.deleteMarkerIterator == null + && this.prefixIterator == null) { + populate(); } - Matcher matcher = HttpUtils.AWS_S3_PREFIX_REGEX.matcher(host); - matcher.lookingAt(); - int end = matcher.end(); + if (this.error == null + && !this.itemIterator.hasNext() + && !this.deleteMarkerIterator.hasNext() + && !this.prefixIterator.hasNext() + && this.listObjectsResult.isTruncated()) { + populate(); + } - this.awsS3Prefix = host.substring(0, end); - if (this.awsS3Prefix.contains("s3-accesspoint") && !https) { - throw new IllegalArgumentException("use HTTPS scheme for host " + host); + if (this.error != null) { + this.completed = true; + return this.error; } - String[] tokens = host.substring(end).split("\\."); - awsDualstack = "dualstack".equals(tokens[0]); - if (awsDualstack) tokens = Arrays.copyOfRange(tokens, 1, tokens.length); - String regionInHost = null; - if (!tokens[0].equals("vpce") && !tokens[0].equals("amazonaws")) { - regionInHost = tokens[0]; - tokens = Arrays.copyOfRange(tokens, 1, tokens.length); + Item item = null; + if (this.itemIterator.hasNext()) { + item = this.itemIterator.next(); + item.setEncodingType(this.listObjectsResult.encodingType()); + this.lastObjectName = item.objectName(); + } else if (this.deleteMarkerIterator.hasNext()) { + item = this.deleteMarkerIterator.next(); + } else if (this.prefixIterator.hasNext()) { + item = this.prefixIterator.next().toItem(); } - this.awsDomainSuffix = String.join(".", tokens); - if (host.equals("s3-external-1.amazonaws.com")) regionInHost = "us-east-1"; - if (host.equals("s3-us-gov-west-1.amazonaws.com") - || host.equals("s3-fips-us-gov-west-1.amazonaws.com")) { - regionInHost = "us-gov-west-1"; + if (item != null) { + item.setEncodingType(this.listObjectsResult.encodingType()); + return new Result<>(item); } - if (regionInHost != null) this.region = regionInHost; + this.completed = true; + throw new NoSuchElementException(); } - private void setBaseUrl(HttpUrl url) { - this.baseUrl = url; - this.setAwsInfo(url.host(), url.isHttps()); - this.useVirtualStyle = this.awsDomainSuffix != null || url.host().endsWith("aliyuncs.com"); + @Override + public void remove() { + throw new UnsupportedOperationException(); } + } - public Builder endpoint(String endpoint) { - setBaseUrl(HttpUtils.getBaseUrl(endpoint)); - return this; - } + /** Execute list objects v1. */ + protected Iterable> objectV1Lister(ListObjectsV1Args args) { + return new Iterable>() { + @Override + public Iterator> iterator() { + return new ObjectIterator() { + private ListBucketResultV1 result = null; - public Builder endpoint(String endpoint, int port, boolean secure) { - HttpUrl url = HttpUtils.getBaseUrl(endpoint); - if (port < 1 || port > 65535) { - throw new IllegalArgumentException("port must be in range of 1 to 65535"); + @Override + protected void populateResult() throws MinioException { + this.listObjectsResult = null; + this.itemIterator = null; + this.prefixIterator = null; + + String nextMarker = (result == null) ? args.marker() : result.nextMarker(); + if (nextMarker == null) nextMarker = this.lastObjectName; + + try { + ListObjectsV1Response response = + listObjectsV1( + ListObjectsV1Args.builder() + .extraHeaders(args.extraHeaders()) + .extraQueryParams(args.extraQueryParams()) + .bucket(args.bucket()) + .region(args.region()) + .delimiter(args.delimiter()) + .encodingType(args.encodingType()) + .maxKeys(args.maxKeys()) + .prefix(args.prefix()) + .marker(nextMarker) + .build()) + .get(); + result = response.result(); + this.listObjectsResult = response.result(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throwEncapsulatedException(e); + } + } + }; } - url = url.newBuilder().port(port).scheme(secure ? "https" : "http").build(); + }; + } - setBaseUrl(url); - return this; - } + /** Execute list objects v2. */ + protected Iterable> objectV2Lister(ListObjectsV2Args args) { + return new Iterable>() { + @Override + public Iterator> iterator() { + return new ObjectIterator() { + private ListBucketResultV2 result = null; - public Builder endpoint(URL url) { - HttpUtils.validateNotNull(url, "url"); - return endpoint(HttpUrl.get(url)); - } + @Override + protected void populateResult() throws MinioException { + this.listObjectsResult = null; + this.itemIterator = null; + this.prefixIterator = null; - public Builder endpoint(HttpUrl url) { - HttpUtils.validateNotNull(url, "url"); - HttpUtils.validateUrl(url); - setBaseUrl(url); - return this; - } + try { + ListObjectsV2Response response = + listObjectsV2( + ListObjectsV2Args.builder() + .extraHeaders(args.extraHeaders()) + .extraQueryParams(args.extraQueryParams()) + .bucket(args.bucket()) + .region(args.region()) + .delimiter(args.delimiter()) + .encodingType(args.encodingType()) + .maxKeys(args.maxKeys()) + .prefix(args.prefix()) + .startAfter(args.startAfter()) + .continuationToken( + result == null + ? args.continuationToken() + : result.nextContinuationToken()) + .fetchOwner(args.fetchOwner()) + .includeUserMetadata(args.includeUserMetadata()) + .build()) + .get(); + result = response.result(); + this.listObjectsResult = response.result(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throwEncapsulatedException(e); + } + } + }; + } + }; + } - public Builder region(String region) { - if (region != null && !HttpUtils.REGION_REGEX.matcher(region).find()) { - throw new IllegalArgumentException("invalid region " + region); + /** Execute list object versions. */ + protected Iterable> objectVersionLister(ListObjectVersionsArgs args) { + return new Iterable>() { + @Override + public Iterator> iterator() { + return new ObjectIterator() { + private ListVersionsResult result = null; + + @Override + protected void populateResult() throws MinioException { + this.listObjectsResult = null; + this.itemIterator = null; + this.prefixIterator = null; + + try { + ListObjectVersionsResponse response = + listObjectVersions( + ListObjectVersionsArgs.builder() + .extraHeaders(args.extraHeaders()) + .extraQueryParams(args.extraQueryParams()) + .bucket(args.bucket()) + .region(args.region()) + .delimiter(args.delimiter()) + .encodingType(args.encodingType()) + .maxKeys(args.maxKeys()) + .prefix(args.prefix()) + .keyMarker(result == null ? args.keyMarker() : result.nextKeyMarker()) + .versionIdMarker( + result == null + ? args.versionIdMarker() + : result.nextVersionIdMarker()) + .build()) + .get(); + result = response.result(); + this.listObjectsResult = response.result(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throwEncapsulatedException(e); + } + } + }; } - this.region = region; - return this; - } + }; + } - public Builder credentials(String accessKey, String secretKey) { - this.provider = new StaticProvider(accessKey, secretKey, null); - return this; - } + ///////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////// ListenBucketNotification API implementation ///////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// - public Builder credentialsProvider(Provider provider) { - this.provider = provider; - return this; + /** Notification result records representation. */ + protected static class NotificationResultRecords { + Response response = null; + Scanner scanner = null; + ObjectMapper mapper = null; + + public NotificationResultRecords(Response response) { + this.response = response; + this.scanner = new Scanner(response.body().charStream()).useDelimiter("\n"); + this.mapper = + JsonMapper.builder() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true) + .build(); } - public Builder httpClient(OkHttpClient httpClient) { - HttpUtils.validateNotNull(httpClient, "http client"); - this.httpClient = httpClient; - return this; - } + /** returns closeable iterator of result of notification records. */ + public CloseableIterator> closeableIterator() { + return new CloseableIterator>() { + String recordsString = null; + NotificationRecords records = null; + boolean isClosed = false; - public Builder httpClient(OkHttpClient httpClient, boolean close) { - HttpUtils.validateNotNull(httpClient, "http client"); - this.httpClient = httpClient; - this.closeHttpClient = close; - return this; - } + @Override + public void close() throws IOException { + if (!isClosed) { + try { + response.body().close(); + scanner.close(); + } finally { + isClosed = true; + } + } + } - public MinioAsyncClient build() { - HttpUtils.validateNotNull(this.baseUrl, "endpoint"); - - if (this.awsDomainSuffix != null - && this.awsDomainSuffix.endsWith(".cn") - && !this.awsS3Prefix.endsWith("s3-accelerate.") - && this.region == null) { - throw new IllegalArgumentException( - "Region missing in Amazon S3 China endpoint " + this.baseUrl); - } + public boolean populate() { + if (isClosed) return false; + if (recordsString != null) return true; - if (this.httpClient == null) { - this.closeHttpClient = true; - this.httpClient = - HttpUtils.newDefaultHttpClient( - DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); - } + while (scanner.hasNext()) { + recordsString = scanner.next().trim(); + if (!recordsString.equals("")) break; + } - return new MinioAsyncClient( - baseUrl, - awsS3Prefix, - awsDomainSuffix, - awsDualstack, - useVirtualStyle, - region, - provider, - httpClient, - closeHttpClient); + if (recordsString == null || recordsString.equals("")) { + try { + close(); + } catch (IOException e) { + isClosed = true; + } + return false; + } + return true; + } + + @Override + public boolean hasNext() { + return populate(); + } + + @Override + public Result next() { + if (isClosed) throw new NoSuchElementException(); + if ((recordsString == null || recordsString.equals("")) && !populate()) { + throw new NoSuchElementException(); + } + + try { + records = mapper.readValue(recordsString, NotificationRecords.class); + return new Result<>(records); + } catch (JsonMappingException | JsonParseException e) { + return new Result<>(new MinioException(e)); + } catch (IOException e) { + return new Result<>(new MinioException(e)); + } finally { + recordsString = null; + records = null; + } + } + }; } } } diff --git a/api/src/main/java/io/minio/MinioClient.java b/api/src/main/java/io/minio/MinioClient.java index 3b2bf5e19..4d2ac06ef 100644 --- a/api/src/main/java/io/minio/MinioClient.java +++ b/api/src/main/java/io/minio/MinioClient.java @@ -17,21 +17,14 @@ package io.minio; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.minio.credentials.Provider; -import io.minio.errors.BucketPolicyTooLargeException; -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 io.minio.errors.MinioException; import io.minio.messages.AccessControlPolicy; -import io.minio.messages.Bucket; import io.minio.messages.CORSConfiguration; -import io.minio.messages.DeleteError; +import io.minio.messages.DeleteResult; import io.minio.messages.Item; import io.minio.messages.LifecycleConfiguration; +import io.minio.messages.ListAllMyBucketsResult; import io.minio.messages.NotificationConfiguration; import io.minio.messages.NotificationRecords; import io.minio.messages.ObjectLockConfiguration; @@ -40,13 +33,8 @@ import io.minio.messages.SseConfiguration; import io.minio.messages.Tags; import io.minio.messages.VersioningConfiguration; -import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.net.URL; -import java.security.InvalidKeyException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -148,21 +136,10 @@ protected MinioClient(MinioClient client) { * * @param args {@link StatObjectArgs} object. * @return {@link StatObjectResponse} - Populated object information and metadata. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. * @see StatObjectResponse */ - public StatObjectResponse statObject(StatObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + public StatObjectResponse statObject(StatObjectArgs args) throws MinioException { try { return asyncClient.statObject(args).get(); } catch (InterruptedException e) { @@ -174,11 +151,11 @@ public StatObjectResponse statObject(StatObjectArgs args) } /** - * Gets data from offset to length of a SSE-C encrypted object. Returned {@link InputStream} must - * be closed after use to release network resources. + * Gets data from offset to length of a SSE-C encrypted object. Returned {@link GetObjectResponse} + * must be closed after use to release network resources. * *
Example:{@code
-   * try (InputStream stream =
+   * try (GetObjectResponse response =
    *     minioClient.getObject(
    *   GetObjectArgs.builder()
    *     .bucket("my-bucketname")
@@ -188,25 +165,15 @@ public StatObjectResponse statObject(StatObjectArgs args)
    *     .ssec(ssec)
    *     .build()
    * ) {
-   *   // Read data from stream
+   *   // Read data from response
+   *   // which is InputStream interface compatible
    * }
    * }
* * @param args Object of {@link GetObjectArgs} - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public GetObjectResponse getObject(GetObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public GetObjectResponse getObject(GetObjectArgs args) throws MinioException { try { return asyncClient.getObject(args).get(); } catch (InterruptedException e) { @@ -231,20 +198,9 @@ public GetObjectResponse getObject(GetObjectArgs args) * } * * @param args Object of {@link DownloadObjectArgs} - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void downloadObject(DownloadObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void downloadObject(DownloadObjectArgs args) throws MinioException { try { asyncClient.downloadObject(args).get(); } catch (InterruptedException e) { @@ -357,20 +313,9 @@ public void downloadObject(DownloadObjectArgs args) * } * * @param args {@link CopyObjectArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public ObjectWriteResponse copyObject(CopyObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public ObjectWriteResponse copyObject(CopyObjectArgs args) throws MinioException { try { return asyncClient.copyObject(args).get(); } catch (InterruptedException e) { @@ -428,20 +373,9 @@ public ObjectWriteResponse copyObject(CopyObjectArgs args) * * @param args {@link ComposeObjectArgs} object. * @return {@link ObjectWriteResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public ObjectWriteResponse composeObject(ComposeObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public ObjectWriteResponse composeObject(ComposeObjectArgs args) throws MinioException { try { return asyncClient.composeObject(args).get(); } catch (InterruptedException e) { @@ -461,7 +395,7 @@ public ObjectWriteResponse composeObject(ComposeObjectArgs args) * String url = * minioClient.getPresignedObjectUrl( * GetPresignedObjectUrlArgs.builder() - * .method(Method.DELETE) + * .method(Http.Method.DELETE) * .bucket("my-bucketname") * .object("my-objectname") * .expiry(24 * 60 * 60) @@ -476,7 +410,7 @@ public ObjectWriteResponse composeObject(ComposeObjectArgs args) * String url = * minioClient.getPresignedObjectUrl( * GetPresignedObjectUrlArgs.builder() - * .method(Method.PUT) + * .method(Http.Method.PUT) * .bucket("my-bucketname") * .object("my-objectname") * .expiry(1, TimeUnit.DAYS) @@ -489,7 +423,7 @@ public ObjectWriteResponse composeObject(ComposeObjectArgs args) * String url = * minioClient.getPresignedObjectUrl( * GetPresignedObjectUrlArgs.builder() - * .method(Method.GET) + * .method(Http.Method.GET) * .bucket("my-bucketname") * .object("my-objectname") * .expiry(2, TimeUnit.HOURS) @@ -499,21 +433,9 @@ public ObjectWriteResponse composeObject(ComposeObjectArgs args) * * @param args {@link GetPresignedObjectUrlArgs} object. * @return String - URL string. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @throws ServerException - */ - public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - XmlParserException, ServerException { + * @throws MinioException thrown to indicate SDK exception. + */ + public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) throws MinioException { return asyncClient.getPresignedObjectUrl(args); } @@ -564,21 +486,10 @@ public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) * * @param policy Post policy of an object. * @return {@code Map} - Contains form-data to upload an object using POST method. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. * @see PostPolicy */ - public Map getPresignedPostFormData(PostPolicy policy) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + public Map getPresignedPostFormData(PostPolicy policy) throws MinioException { return asyncClient.getPresignedPostFormData(policy); } @@ -609,20 +520,9 @@ public Map getPresignedPostFormData(PostPolicy policy) * } * * @param args {@link RemoveObjectArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void removeObject(RemoveObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void removeObject(RemoveObjectArgs args) throws MinioException { try { asyncClient.removeObject(args).get(); } catch (InterruptedException e) { @@ -641,20 +541,21 @@ public void removeObject(RemoveObjectArgs args) * objects.add(new DeleteObject("my-objectname1")); * objects.add(new DeleteObject("my-objectname2")); * objects.add(new DeleteObject("my-objectname3")); - * Iterable> results = + * Iterable> results = * minioClient.removeObjects( * RemoveObjectsArgs.builder().bucket("my-bucketname").objects(objects).build()); - * for (Result result : results) { - * DeleteError error = result.get(); + * for (Result result : results) { + * DeleteResult.Error error = result.get(); * System.out.println( * "Error in deleting object " + error.objectName() + "; " + error.message()); * } * } * * @param args {@link RemoveObjectsArgs} object. - * @return {@code Iterable>} - Lazy iterator contains object removal status. + * @return {@code Iterable>} - Lazy iterator contains object removal + * status. */ - public Iterable> removeObjects(RemoveObjectsArgs args) { + public Iterable> removeObjects(RemoveObjectsArgs args) { return asyncClient.removeObjects(args); } @@ -681,20 +582,9 @@ public Iterable> removeObjects(RemoveObjectsArgs args) { * } * * @param args {@link RestoreObjectArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void restoreObject(RestoreObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void restoreObject(RestoreObjectArgs args) throws MinioException { try { asyncClient.restoreObject(args).get(); } catch (InterruptedException e) { @@ -745,7 +635,6 @@ public void restoreObject(RestoreObjectArgs args) * * @param args Instance of {@link ListObjectsArgs} built using the builder * @return {@code Iterable>} - Lazy iterator contains object information. - * @throws XmlParserException upon parsing response xml */ public Iterable> listObjects(ListObjectsArgs args) { return asyncClient.listObjects(args); @@ -755,27 +644,16 @@ public Iterable> listObjects(ListObjectsArgs args) { * Lists bucket information of all buckets. * *
Example:{@code
-   * List bucketList = minioClient.listBuckets();
+   * List bucketList = minioClient.listBuckets();
    * for (Bucket bucket : bucketList) {
    *   System.out.println(bucket.creationDate() + ", " + bucket.name());
    * }
    * }
* - * @return {@code List} - List of bucket information. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public List listBuckets() - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @return {@code List} - List of bucket information. + * @throws MinioException thrown to indicate SDK exception. + */ + public List listBuckets() throws MinioException { try { return asyncClient.listBuckets().get(); } catch (InterruptedException e) { @@ -790,16 +668,17 @@ public List listBuckets() * Lists bucket information of all buckets. * *
Example:{@code
-   * Iterable> results = minioClient.listBuckets(ListBucketsArgs.builder().build());
-   * for (Result result : results) {
+   * Iterable> results = minioClient.listBuckets(ListBucketsArgs.builder().build());
+   * for (Result result : results) {
    *   Bucket bucket = result.get();
    *   System.out.println(String.format("Bucket: %s, Region: %s, CreationDate: %s", bucket.name(), bucket.bucketRegion(), bucket.creationDate()));
    * }
    * }
* - * @return {@link Iterable}<{@link List}<{@link Bucket}>> object. + * @return {@link Iterable}<{@link List}<{@link ListAllMyBucketsResult.Bucket}>> + * object. */ - public Iterable> listBuckets(ListBucketsArgs args) { + public Iterable> listBuckets(ListBucketsArgs args) { return asyncClient.listBuckets(args); } @@ -818,20 +697,9 @@ public Iterable> listBuckets(ListBucketsArgs args) { * * @param args {@link BucketExistsArgs} object. * @return boolean - True if the bucket exists. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public boolean bucketExists(BucketExistsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public boolean bucketExists(BucketExistsArgs args) throws MinioException { try { return asyncClient.bucketExists(args).get(); } catch (InterruptedException e) { @@ -869,20 +737,9 @@ public boolean bucketExists(BucketExistsArgs args) * } * * @param args Object with bucket name, region and lock functionality - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void makeBucket(MakeBucketArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void makeBucket(MakeBucketArgs args) throws MinioException { try { asyncClient.makeBucket(args).get(); } catch (InterruptedException e) { @@ -901,20 +758,9 @@ public void makeBucket(MakeBucketArgs args) * } * * @param args {@link SetBucketVersioningArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketVersioning(SetBucketVersioningArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketVersioning(SetBucketVersioningArgs args) throws MinioException { try { asyncClient.setBucketVersioning(args).get(); } catch (InterruptedException e) { @@ -935,20 +781,10 @@ public void setBucketVersioning(SetBucketVersioningArgs args) * * @param args {@link GetBucketVersioningArgs} object. * @return {@link VersioningConfiguration} - Versioning configuration. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public VersioningConfiguration getBucketVersioning(GetBucketVersioningArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.getBucketVersioning(args).get(); } catch (InterruptedException e) { @@ -970,20 +806,10 @@ public VersioningConfiguration getBucketVersioning(GetBucketVersioningArgs args) * } * * @param args {@link SetObjectLockConfigurationArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public void setObjectLockConfiguration(SetObjectLockConfigurationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { asyncClient.setObjectLockConfiguration(args).get(); } catch (InterruptedException e) { @@ -1002,20 +828,10 @@ public void setObjectLockConfiguration(SetObjectLockConfigurationArgs args) * } * * @param args {@link DeleteObjectLockConfigurationArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public void deleteObjectLockConfiguration(DeleteObjectLockConfigurationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { asyncClient.deleteObjectLockConfiguration(args).get(); } catch (InterruptedException e) { @@ -1039,20 +855,10 @@ public void deleteObjectLockConfiguration(DeleteObjectLockConfigurationArgs args * * @param args {@link GetObjectLockConfigurationArgs} object. * @return {@link ObjectLockConfiguration} - Default retention configuration. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public ObjectLockConfiguration getObjectLockConfiguration(GetObjectLockConfigurationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.getObjectLockConfiguration(args).get(); } catch (InterruptedException e) { @@ -1079,20 +885,9 @@ public ObjectLockConfiguration getObjectLockConfiguration(GetObjectLockConfigura * } * * @param args {@link SetObjectRetentionArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setObjectRetention(SetObjectRetentionArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setObjectRetention(SetObjectRetentionArgs args) throws MinioException { try { asyncClient.setObjectRetention(args).get(); } catch (InterruptedException e) { @@ -1118,20 +913,9 @@ public void setObjectRetention(SetObjectRetentionArgs args) * * @param args {@link GetObjectRetentionArgs} object. * @return {@link Retention} - Object retention configuration. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public Retention getObjectRetention(GetObjectRetentionArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public Retention getObjectRetention(GetObjectRetentionArgs args) throws MinioException { try { return asyncClient.getObjectRetention(args).get(); } catch (InterruptedException e) { @@ -1155,20 +939,9 @@ public Retention getObjectRetention(GetObjectRetentionArgs args) * } * * @param args {@link EnableObjectLegalHoldArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void enableObjectLegalHold(EnableObjectLegalHoldArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void enableObjectLegalHold(EnableObjectLegalHoldArgs args) throws MinioException { try { asyncClient.enableObjectLegalHold(args).get(); } catch (InterruptedException e) { @@ -1191,20 +964,9 @@ public void enableObjectLegalHold(EnableObjectLegalHoldArgs args) * } * * @param args {@link DisableObjectLegalHoldArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void disableObjectLegalHold(DisableObjectLegalHoldArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void disableObjectLegalHold(DisableObjectLegalHoldArgs args) throws MinioException { try { asyncClient.disableObjectLegalHold(args).get(); } catch (InterruptedException e) { @@ -1235,20 +997,9 @@ public void disableObjectLegalHold(DisableObjectLegalHoldArgs args) * args {@link IsObjectLegalHoldEnabledArgs} object. * * @return boolean - True if legal hold is enabled. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public boolean isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public boolean isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs args) throws MinioException { try { return asyncClient.isObjectLegalHoldEnabled(args).get(); } catch (InterruptedException e) { @@ -1267,20 +1018,9 @@ public boolean isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs args) * } * * @param args {@link RemoveBucketArgs} bucket. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void removeBucket(RemoveBucketArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void removeBucket(RemoveBucketArgs args) throws MinioException { try { asyncClient.removeBucket(args).get(); } catch (InterruptedException e) { @@ -1336,20 +1076,9 @@ public void removeBucket(RemoveBucketArgs args) * * @param args {@link PutObjectArgs} object. * @return {@link ObjectWriteResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public ObjectWriteResponse putObject(PutObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public ObjectWriteResponse putObject(PutObjectArgs args) throws MinioException { try { return asyncClient.putObject(args).get(); } catch (InterruptedException e) { @@ -1381,20 +1110,9 @@ public ObjectWriteResponse putObject(PutObjectArgs args) * * @param args {@link UploadObjectArgs} object. * @return {@link ObjectWriteResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public ObjectWriteResponse uploadObject(UploadObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public ObjectWriteResponse uploadObject(UploadObjectArgs args) throws MinioException { try { return asyncClient.uploadObject(args).get(); } catch (InterruptedException e) { @@ -1415,21 +1133,9 @@ public ObjectWriteResponse uploadObject(UploadObjectArgs args) * * @param args {@link GetBucketPolicyArgs} object. * @return String - Bucket policy configuration as JSON string. - * @throws BucketPolicyTooLargeException thrown to indicate returned bucket policy is too large. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public String getBucketPolicy(GetBucketPolicyArgs args) - throws BucketPolicyTooLargeException, ErrorResponseException, InsufficientDataException, - InternalException, InvalidKeyException, InvalidResponseException, IOException, - NoSuchAlgorithmException, ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public String getBucketPolicy(GetBucketPolicyArgs args) throws MinioException { try { return asyncClient.getBucketPolicy(args).get(); } catch (InterruptedException e) { @@ -1471,20 +1177,9 @@ public String getBucketPolicy(GetBucketPolicyArgs args) * } * * @param args {@link SetBucketPolicyArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketPolicy(SetBucketPolicyArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketPolicy(SetBucketPolicyArgs args) throws MinioException { try { asyncClient.setBucketPolicy(args).get(); } catch (InterruptedException e) { @@ -1502,20 +1197,9 @@ public void setBucketPolicy(SetBucketPolicyArgs args) * } * * @param args {@link DeleteBucketPolicyArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketPolicy(DeleteBucketPolicyArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketPolicy(DeleteBucketPolicyArgs args) throws MinioException { try { asyncClient.deleteBucketPolicy(args).get(); } catch (InterruptedException e) { @@ -1546,20 +1230,9 @@ public void deleteBucketPolicy(DeleteBucketPolicyArgs args) * } * * @param args {@link SetBucketLifecycleArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketLifecycle(SetBucketLifecycleArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketLifecycle(SetBucketLifecycleArgs args) throws MinioException { try { asyncClient.setBucketLifecycle(args).get(); } catch (InterruptedException e) { @@ -1577,20 +1250,9 @@ public void setBucketLifecycle(SetBucketLifecycleArgs args) * } * * @param args {@link DeleteBucketLifecycleArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketLifecycle(DeleteBucketLifecycleArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketLifecycle(DeleteBucketLifecycleArgs args) throws MinioException { try { asyncClient.deleteBucketLifecycle(args).get(); } catch (InterruptedException e) { @@ -1612,20 +1274,10 @@ public void deleteBucketLifecycle(DeleteBucketLifecycleArgs args) * @param args {@link GetBucketLifecycleArgs} object. * @return {@link LifecycleConfiguration} object. * @return String - Life cycle configuration as XML string. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public LifecycleConfiguration getBucketLifecycle(GetBucketLifecycleArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.getBucketLifecycle(args).get(); } catch (InterruptedException e) { @@ -1647,20 +1299,10 @@ public LifecycleConfiguration getBucketLifecycle(GetBucketLifecycleArgs args) * * @param args {@link GetBucketNotificationArgs} object. * @return {@link NotificationConfiguration} - Notification configuration. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public NotificationConfiguration getBucketNotification(GetBucketNotificationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.getBucketNotification(args).get(); } catch (InterruptedException e) { @@ -1696,20 +1338,9 @@ public NotificationConfiguration getBucketNotification(GetBucketNotificationArgs * } * * @param args {@link SetBucketNotificationArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketNotification(SetBucketNotificationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketNotification(SetBucketNotificationArgs args) throws MinioException { try { asyncClient.setBucketNotification(args).get(); } catch (InterruptedException e) { @@ -1728,20 +1359,9 @@ public void setBucketNotification(SetBucketNotificationArgs args) * } * * @param args {@link DeleteBucketNotificationArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketNotification(DeleteBucketNotificationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketNotification(DeleteBucketNotificationArgs args) throws MinioException { try { asyncClient.deleteBucketNotification(args).get(); } catch (InterruptedException e) { @@ -1762,20 +1382,10 @@ public void deleteBucketNotification(DeleteBucketNotificationArgs args) * * @param args {@link GetBucketReplicationArgs} object. * @return {@link ReplicationConfiguration} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public ReplicationConfiguration getBucketReplication(GetBucketReplicationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.getBucketReplication(args).get(); } catch (InterruptedException e) { @@ -1818,20 +1428,9 @@ public ReplicationConfiguration getBucketReplication(GetBucketReplicationArgs ar * } * * @param args {@link SetBucketReplicationArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketReplication(SetBucketReplicationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketReplication(SetBucketReplicationArgs args) throws MinioException { try { asyncClient.setBucketReplication(args).get(); } catch (InterruptedException e) { @@ -1850,20 +1449,9 @@ public void setBucketReplication(SetBucketReplicationArgs args) * } * * @param args {@link DeleteBucketReplicationArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketReplication(DeleteBucketReplicationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketReplication(DeleteBucketReplicationArgs args) throws MinioException { try { asyncClient.deleteBucketReplication(args).get(); } catch (InterruptedException e) { @@ -1902,21 +1490,10 @@ public void deleteBucketReplication(DeleteBucketReplicationArgs args) * @param args {@link ListenBucketNotificationArgs} object. * @return {@code CloseableIterator>} - Lazy closable iterator * contains event records. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public CloseableIterator> listenBucketNotification( - ListenBucketNotificationArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + ListenBucketNotificationArgs args) throws MinioException { return asyncClient.listenBucketNotification(args); } @@ -1955,20 +1532,10 @@ public CloseableIterator> listenBucketNotification( * * @param args instance of {@link SelectObjectContentArgs} * @return {@link SelectResponseStream} - Contains filtered records and progress. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public SelectResponseStream selectObjectContent(SelectObjectContentArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { return asyncClient.selectObjectContent(args); } @@ -1981,20 +1548,9 @@ public SelectResponseStream selectObjectContent(SelectObjectContentArgs args) * } * * @param args {@link SetBucketEncryptionArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketEncryption(SetBucketEncryptionArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketEncryption(SetBucketEncryptionArgs args) throws MinioException { try { asyncClient.setBucketEncryption(args).get(); } catch (InterruptedException e) { @@ -2015,20 +1571,9 @@ public void setBucketEncryption(SetBucketEncryptionArgs args) * * @param args {@link GetBucketEncryptionArgs} object. * @return {@link SseConfiguration} - Server-side encryption configuration. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public SseConfiguration getBucketEncryption(GetBucketEncryptionArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public SseConfiguration getBucketEncryption(GetBucketEncryptionArgs args) throws MinioException { try { return asyncClient.getBucketEncryption(args).get(); } catch (InterruptedException e) { @@ -2048,20 +1593,9 @@ public SseConfiguration getBucketEncryption(GetBucketEncryptionArgs args) * } * * @param args {@link DeleteBucketEncryptionArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketEncryption(DeleteBucketEncryptionArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketEncryption(DeleteBucketEncryptionArgs args) throws MinioException { try { asyncClient.deleteBucketEncryption(args).get(); } catch (InterruptedException e) { @@ -2081,20 +1615,9 @@ public void deleteBucketEncryption(DeleteBucketEncryptionArgs args) * * @param args {@link GetBucketTagsArgs} object. * @return {@link Tags} - Tags. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public Tags getBucketTags(GetBucketTagsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public Tags getBucketTags(GetBucketTagsArgs args) throws MinioException { try { return asyncClient.getBucketTags(args).get(); } catch (InterruptedException e) { @@ -2117,20 +1640,9 @@ public Tags getBucketTags(GetBucketTagsArgs args) * } * * @param args {@link SetBucketTagsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketTags(SetBucketTagsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketTags(SetBucketTagsArgs args) throws MinioException { try { asyncClient.setBucketTags(args).get(); } catch (InterruptedException e) { @@ -2148,20 +1660,9 @@ public void setBucketTags(SetBucketTagsArgs args) * } * * @param args {@link DeleteBucketTagsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketTags(DeleteBucketTagsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketTags(DeleteBucketTagsArgs args) throws MinioException { try { asyncClient.deleteBucketTags(args).get(); } catch (InterruptedException e) { @@ -2182,20 +1683,9 @@ public void deleteBucketTags(DeleteBucketTagsArgs args) * * @param args {@link GetObjectTagsArgs} object. * @return {@link Tags} - Tags. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public Tags getObjectTags(GetObjectTagsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public Tags getObjectTags(GetObjectTagsArgs args) throws MinioException { try { return asyncClient.getObjectTags(args).get(); } catch (InterruptedException e) { @@ -2222,20 +1712,9 @@ public Tags getObjectTags(GetObjectTagsArgs args) * } * * @param args {@link SetObjectTagsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setObjectTags(SetObjectTagsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setObjectTags(SetObjectTagsArgs args) throws MinioException { try { asyncClient.setObjectTags(args).get(); } catch (InterruptedException e) { @@ -2254,20 +1733,9 @@ public void setObjectTags(SetObjectTagsArgs args) * } * * @param args {@link DeleteObjectTagsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteObjectTags(DeleteObjectTagsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteObjectTags(DeleteObjectTagsArgs args) throws MinioException { try { asyncClient.deleteObjectTags(args).get(); } catch (InterruptedException e) { @@ -2287,20 +1755,9 @@ public void deleteObjectTags(DeleteObjectTagsArgs args) * * @param args {@link GetBucketCorsArgs} object. * @return {@link CORSConfiguration} - CORSConfiguration. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CORSConfiguration getBucketCors(GetBucketCorsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public CORSConfiguration getBucketCors(GetBucketCorsArgs args) throws MinioException { try { return asyncClient.getBucketCors(args).get(); } catch (InterruptedException e) { @@ -2343,20 +1800,9 @@ public CORSConfiguration getBucketCors(GetBucketCorsArgs args) * } * * @param args {@link SetBucketCorsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void setBucketCors(SetBucketCorsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void setBucketCors(SetBucketCorsArgs args) throws MinioException { try { asyncClient.setBucketCors(args).get(); } catch (InterruptedException e) { @@ -2374,20 +1820,9 @@ public void setBucketCors(SetBucketCorsArgs args) * } * * @param args {@link DeleteBucketCorsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public void deleteBucketCors(DeleteBucketCorsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public void deleteBucketCors(DeleteBucketCorsArgs args) throws MinioException { try { asyncClient.deleteBucketCors(args).get(); } catch (InterruptedException e) { @@ -2408,20 +1843,9 @@ public void deleteBucketCors(DeleteBucketCorsArgs args) * * @param args {@link GetObjectAclArgs} object. * @return {@link AccessControlPolicy} - Access control policy object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public AccessControlPolicy getObjectAcl(GetObjectAclArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public AccessControlPolicy getObjectAcl(GetObjectAclArgs args) throws MinioException { try { return asyncClient.getObjectAcl(args).get(); } catch (InterruptedException e) { @@ -2450,20 +1874,10 @@ public AccessControlPolicy getObjectAcl(GetObjectAclArgs args) * * @param args {@link GetObjectAttributesArgs} object. * @return {@link GetObjectAttributesResponse} - Response object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public GetObjectAttributesResponse getObjectAttributes(GetObjectAttributesArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.getObjectAttributes(args).get(); } catch (InterruptedException e) { @@ -2498,20 +1912,10 @@ public GetObjectAttributesResponse getObjectAttributes(GetObjectAttributesArgs a * } * * @param args {@link UploadSnowballObjectsArgs} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. + * @throws MinioException thrown to indicate SDK exception. */ public ObjectWriteResponse uploadSnowballObjects(UploadSnowballObjectsArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + throws MinioException { try { return asyncClient.uploadSnowballObjects(args).get(); } catch (InterruptedException e) { @@ -2544,20 +1948,9 @@ public ObjectWriteResponse uploadSnowballObjects(UploadSnowballObjectsArgs args) * * @param args {@link PutObjectFanOutArgs} object. * @return {@link PutObjectFanOutResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public PutObjectFanOutResponse putObjectFanOut(PutObjectFanOutArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public PutObjectFanOutResponse putObjectFanOut(PutObjectFanOutArgs args) throws MinioException { try { return asyncClient.putObjectFanOut(args).get(); } catch (InterruptedException e) { @@ -2573,20 +1966,9 @@ public PutObjectFanOutResponse putObjectFanOut(PutObjectFanOutArgs args) * * @param args {@link PromptObjectArgs} object. * @return {@link PromptObjectResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public PromptObjectResponse promptObject(PromptObjectArgs args) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { + * @throws MinioException thrown to indicate SDK exception. + */ + public PromptObjectResponse promptObject(PromptObjectArgs args) throws MinioException { try { return asyncClient.promptObject(args).get(); } catch (InterruptedException e) { @@ -2621,11 +2003,12 @@ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) * minioClient.ignoreCertCheck(); * } * - * @throws KeyManagementException thrown to indicate key management error. - * @throws NoSuchAlgorithmException thrown to indicate missing of SSL library. + * @throws MinioException thrown to indicate SDK exception. */ - @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.") - public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmException { + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SIC", + justification = "Should not be used in production anyways.") + public void ignoreCertCheck() throws MinioException { asyncClient.ignoreCertCheck(); } @@ -2654,32 +2037,11 @@ public void traceOn(OutputStream traceStream) { * Disables HTTP call tracing previously enabled. * * @see #traceOn - * @throws IOException upon connection error */ - public void traceOff() throws IOException { + public void traceOff() { asyncClient.traceOff(); } - /** - * Enables accelerate endpoint for Amazon S3 endpoint. - * - * @deprecated This method is no longer supported. - */ - @Deprecated - public void enableAccelerateEndpoint() { - asyncClient.enableAccelerateEndpoint(); - } - - /** - * Disables accelerate endpoint for Amazon S3 endpoint. - * - * @deprecated This method is no longer supported. - */ - @Deprecated - public void disableAccelerateEndpoint() { - asyncClient.disableAccelerateEndpoint(); - } - /** Enables dual-stack endpoint for Amazon S3 endpoint. */ public void enableDualStackEndpoint() { asyncClient.enableDualStackEndpoint(); diff --git a/api/src/main/java/io/minio/MinioProperties.java b/api/src/main/java/io/minio/MinioProperties.java deleted file mode 100644 index 95673050a..000000000 --- a/api/src/main/java/io/minio/MinioProperties.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicReference; -import java.util.jar.Manifest; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** Identifies and stores version information of minio-java package at run time. */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "MS_EXPOSE_REP") -public enum MinioProperties { - INSTANCE; - - private static final Logger LOGGER = Logger.getLogger(MinioProperties.class.getName()); - - private final AtomicReference version = new AtomicReference<>(null); - - public String getVersion() { - String result = version.get(); - if (result != null) { - return result; - } - setVersion(); - return version.get(); - } - - private synchronized void setVersion() { - if (version.get() != null) { - return; - } - version.set("dev"); - ClassLoader classLoader = getClass().getClassLoader(); - if (classLoader == null) { - return; - } - - try { - Enumeration resources = classLoader.getResources("META-INF/MANIFEST.MF"); - while (resources.hasMoreElements()) { - try (InputStream is = resources.nextElement().openStream()) { - Manifest manifest = new Manifest(is); - if ("minio".equals(manifest.getMainAttributes().getValue("Implementation-Title"))) { - version.set(manifest.getMainAttributes().getValue("Implementation-Version")); - return; - } - } - } - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "IOException occurred", e); - version.set("unknown"); - } - } - - public String getDefaultUserAgent() { - return "MinIO (" - + System.getProperty("os.name") - + "; " - + System.getProperty("os.arch") - + ") minio-java/" - + getVersion(); - } -} diff --git a/api/src/main/java/io/minio/ObjectArgs.java b/api/src/main/java/io/minio/ObjectArgs.java index 6ec9c4f46..8d33d44c6 100644 --- a/api/src/main/java/io/minio/ObjectArgs.java +++ b/api/src/main/java/io/minio/ObjectArgs.java @@ -18,19 +18,31 @@ import java.util.Objects; -/** Base argument class holds object name and version ID along with bucket information. */ +/** + * Common arguments of {@link AbortMultipartUploadArgs}, {@link CompleteMultipartUploadArgs}, {@link + * CreateMultipartUploadArgs}, {@link ListPartsArgs}, {@link ObjectVersionArgs}, {@link + * ObjectWriteArgs}, {@link PromptObjectArgs}, {@link PutObjectAPIBaseArgs} and {@link + * UploadPartCopyArgs}. + */ public abstract class ObjectArgs extends BucketArgs { protected String objectName; + protected ObjectArgs() {} + + protected ObjectArgs(ObjectArgs args) { + super(args); + this.objectName = args.objectName; + } + public String object() { return objectName; } - /** Base argument builder class for {@link ObjectArgs}. */ + /** Builder of {@link ObjectArgs}. */ public abstract static class Builder, A extends ObjectArgs> extends BucketArgs.Builder { protected void validateObjectName(String name) { - validateNotEmptyString(name, "object name"); + Utils.validateNotEmptyString(name, "object name"); if (skipValidation) { return; } diff --git a/api/src/main/java/io/minio/ObjectConditionalReadArgs.java b/api/src/main/java/io/minio/ObjectConditionalReadArgs.java index bdbf9cf67..2fbdf896b 100644 --- a/api/src/main/java/io/minio/ObjectConditionalReadArgs.java +++ b/api/src/main/java/io/minio/ObjectConditionalReadArgs.java @@ -16,13 +16,12 @@ package io.minio; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; import java.time.ZonedDateTime; import java.util.Objects; -/** Base argument class holds condition properties for reading object. */ +/** + * Common arguments of {@link SourceObject}, {@link GetObjectArgs} and {@link HeadObjectBaseArgs}. + */ public abstract class ObjectConditionalReadArgs extends ObjectReadArgs { protected Long offset; protected Long length; @@ -30,6 +29,33 @@ public abstract class ObjectConditionalReadArgs extends ObjectReadArgs { protected String notMatchETag; protected ZonedDateTime modifiedSince; protected ZonedDateTime unmodifiedSince; + protected boolean fetchChecksum; + + protected ObjectConditionalReadArgs() {} + + protected ObjectConditionalReadArgs(SourceObject args) { + super(args); + } + + protected ObjectConditionalReadArgs(DownloadObjectArgs args) { + super(args); + } + + protected ObjectConditionalReadArgs(ObjectConditionalReadArgs args) { + super(args); + this.offset = args.offset; + this.length = args.length; + this.matchETag = args.matchETag; + this.notMatchETag = args.notMatchETag; + this.modifiedSince = args.modifiedSince; + this.unmodifiedSince = args.unmodifiedSince; + this.fetchChecksum = args.fetchChecksum; + } + + protected ObjectConditionalReadArgs(ObjectConditionalReadArgs args, String matchETag) { + this(args); + this.matchETag = args.matchETag; + } public Long offset() { return offset; @@ -55,7 +81,11 @@ public ZonedDateTime unmodifiedSince() { return unmodifiedSince; } - public Multimap getHeaders() { + public boolean fetchChecksum() { + return fetchChecksum; + } + + public Http.Headers makeHeaders() { Long offset = this.offset; Long length = this.length; if (length != null && offset == null) { @@ -70,7 +100,7 @@ public Multimap getHeaders() { } } - Multimap headers = HashMultimap.create(); + Http.Headers headers = new Http.Headers(ssec == null ? null : ssec.headers()); if (range != null) headers.put("Range", range); if (matchETag != null) headers.put("if-match", matchETag); @@ -84,22 +114,20 @@ public Multimap getHeaders() { headers.put("if-unmodified-since", unmodifiedSince.format(Time.HTTP_HEADER_DATE_FORMAT)); } - if (ssec != null) headers.putAll(Multimaps.forMap(ssec.headers())); + if (fetchChecksum) headers.put("x-amz-checksum-mode", "ENABLED"); return headers; } - public Multimap genCopyHeaders() { - Multimap headers = HashMultimap.create(); - - String copySource = S3Escaper.encodePath("/" + bucketName + "/" + objectName); + public Http.Headers makeCopyHeaders() { + String copySource = Utils.encodePath("/" + bucketName + "/" + objectName); if (versionId != null) { - copySource += "?versionId=" + S3Escaper.encode(versionId); + copySource += "?versionId=" + Utils.encode(versionId); } - headers.put("x-amz-copy-source", copySource); + Http.Headers headers = new Http.Headers("x-amz-copy-source", copySource); - if (ssec != null) headers.putAll(Multimaps.forMap(ssec.copySourceHeaders())); + if (ssec != null) headers.putAll(ssec.copySourceHeaders()); if (matchETag != null) headers.put("x-amz-copy-source-if-match", matchETag); if (notMatchETag != null) headers.put("x-amz-copy-source-if-none-match", notMatchETag); @@ -118,7 +146,7 @@ public Multimap genCopyHeaders() { return headers; } - /** Base argument builder class for {@link ObjectConditionalReadArgs}. */ + /** Builder of {@link ObjectConditionalReadArgs}. */ @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class public abstract static class Builder, A extends ObjectConditionalReadArgs> extends ObjectReadArgs.Builder { @@ -147,13 +175,13 @@ public B length(Long length) { } public B matchETag(String etag) { - validateNullOrNotEmptyString(etag, "etag"); + Utils.validateNullOrNotEmptyString(etag, "etag"); operations.add(args -> args.matchETag = etag); return (B) this; } public B notMatchETag(String etag) { - validateNullOrNotEmptyString(etag, "etag"); + Utils.validateNullOrNotEmptyString(etag, "etag"); operations.add(args -> args.notMatchETag = etag); return (B) this; } @@ -167,6 +195,11 @@ public B unmodifiedSince(ZonedDateTime unmodifiedTime) { operations.add(args -> args.unmodifiedSince = unmodifiedTime); return (B) this; } + + public B fetchChecksum(boolean flag) { + operations.add(args -> args.fetchChecksum = flag); + return (B) this; + } } @Override @@ -180,12 +213,20 @@ public boolean equals(Object o) { && Objects.equals(matchETag, that.matchETag) && Objects.equals(notMatchETag, that.notMatchETag) && Objects.equals(modifiedSince, that.modifiedSince) - && Objects.equals(unmodifiedSince, that.unmodifiedSince); + && Objects.equals(unmodifiedSince, that.unmodifiedSince) + && Objects.equals(fetchChecksum, that.fetchChecksum); } @Override public int hashCode() { return Objects.hash( - super.hashCode(), offset, length, matchETag, notMatchETag, modifiedSince, unmodifiedSince); + super.hashCode(), + offset, + length, + matchETag, + notMatchETag, + modifiedSince, + unmodifiedSince, + fetchChecksum); } } diff --git a/api/src/main/java/io/minio/ObjectReadArgs.java b/api/src/main/java/io/minio/ObjectReadArgs.java index 2c36048f1..d5dfaefea 100644 --- a/api/src/main/java/io/minio/ObjectReadArgs.java +++ b/api/src/main/java/io/minio/ObjectReadArgs.java @@ -17,25 +17,34 @@ package io.minio; import java.util.Objects; -import okhttp3.HttpUrl; -/** Base argument class for reading object. */ +/** + * Common arguments of {@link DownloadObjectArgs}, {@link GetObjectAttributesArgs}, {@link + * ObjectConditionalReadArgs} and {@link SelectObjectContentArgs}. + */ public abstract class ObjectReadArgs extends ObjectVersionArgs { - protected ServerSideEncryptionCustomerKey ssec; + protected ServerSideEncryption.CustomerKey ssec; + + protected ObjectReadArgs() {} + + protected ObjectReadArgs(ObjectReadArgs args) { + super(args); + this.ssec = args.ssec; + } - public ServerSideEncryptionCustomerKey ssec() { + public ServerSideEncryption.CustomerKey ssec() { return ssec; } - protected void validateSsec(HttpUrl url) { - checkSse(ssec, url); + protected void validateSsec(boolean isHttps) { + checkSse(ssec, isHttps); } - /** Base argument builder class for {@link ObjectReadArgs}. */ + /** Builder of {@link ObjectReadArgs}. */ public abstract static class Builder, A extends ObjectReadArgs> extends ObjectVersionArgs.Builder { @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class - public B ssec(ServerSideEncryptionCustomerKey ssec) { + public B ssec(ServerSideEncryption.CustomerKey ssec) { operations.add(args -> args.ssec = ssec); return (B) this; } diff --git a/api/src/main/java/io/minio/ObjectVersionArgs.java b/api/src/main/java/io/minio/ObjectVersionArgs.java index 528fc02cd..3f57d1f9e 100644 --- a/api/src/main/java/io/minio/ObjectVersionArgs.java +++ b/api/src/main/java/io/minio/ObjectVersionArgs.java @@ -18,15 +18,28 @@ import java.util.Objects; -/** Base argument class holds object name and version ID along with bucket information. */ +/** + * Common arguments of {@link DeleteObjectTagsArgs}, {@link DisableObjectLegalHoldArgs}, {@link + * EnableObjectLegalHoldArgs}, {@link GetObjectAclArgs}, {@link GetObjectRetentionArgs}, {@link + * GetObjectTagsArgs}, {@link GetPresignedObjectUrlArgs}, {@link IsObjectLegalHoldEnabledArgs}, + * {@link ObjectReadArgs}, {@link ObjectVersionArgs}, {@link RemoveObjectArgs}, {@link + * RestoreObjectArgs}, {@link SetObjectRetentionArgs} and {@link SetObjectTagsArgs}. + */ public abstract class ObjectVersionArgs extends ObjectArgs { protected String versionId; + protected ObjectVersionArgs() {} + + protected ObjectVersionArgs(ObjectVersionArgs args) { + super(args); + this.versionId = args.versionId; + } + public String versionId() { return versionId; } - /** Base argument builder class for {@link ObjectVersionArgs}. */ + /** Builder of {@link ObjectVersionArgs}. */ public abstract static class Builder, A extends ObjectVersionArgs> extends ObjectArgs.Builder { @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class diff --git a/api/src/main/java/io/minio/ObjectWriteArgs.java b/api/src/main/java/io/minio/ObjectWriteArgs.java index b7d76613b..3e79ed224 100644 --- a/api/src/main/java/io/minio/ObjectWriteArgs.java +++ b/api/src/main/java/io/minio/ObjectWriteArgs.java @@ -16,18 +16,19 @@ package io.minio; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; import io.minio.messages.Retention; import io.minio.messages.Tags; +import java.io.IOException; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; -import okhttp3.HttpUrl; +import okhttp3.MediaType; -/** Base argument class for writing object. */ +/** + * Common arguments of {@link UploadSnowballObjectsArgs}, {@link UploadSnowballObjectsArgs}, {@link + * PutObjectBaseArgs}, {@link ComposeObjectArgs} and {@link CopyObjectArgs}. + */ public abstract class ObjectWriteArgs extends ObjectArgs { // allowed maximum object size is 5TiB. public static final long MAX_OBJECT_SIZE = 5L * 1024 * 1024 * 1024 * 1024; @@ -37,20 +38,30 @@ public abstract class ObjectWriteArgs extends ObjectArgs { public static final long MAX_PART_SIZE = 5L * 1024 * 1024 * 1024; public static final int MAX_MULTIPART_COUNT = 10000; - protected Multimap headers = - Multimaps.unmodifiableMultimap(HashMultimap.create()); - protected Multimap userMetadata = - Multimaps.unmodifiableMultimap(HashMultimap.create()); + protected Http.Headers headers; + protected Http.Headers userMetadata; protected ServerSideEncryption sse; protected Tags tags = new Tags(); protected Retention retention; protected boolean legalHold; - public Multimap headers() { + protected ObjectWriteArgs() {} + + protected ObjectWriteArgs(ObjectWriteArgs args) { + super(args); + this.headers = args.headers; + this.userMetadata = args.userMetadata; + this.sse = args.sse; + this.tags = args.tags; + this.retention = args.retention; + this.legalHold = args.legalHold; + } + + public Http.Headers headers() { return headers; } - public Multimap userMetadata() { + public Http.Headers userMetadata() { return userMetadata; } @@ -70,74 +81,73 @@ public boolean legalHold() { return legalHold; } - public Multimap genHeaders() { - Multimap headers = HashMultimap.create(); + public MediaType contentType() throws IOException { + return (headers != null && headers.getFirst(Http.Headers.CONTENT_TYPE) != null) + ? MediaType.parse(headers.getFirst(Http.Headers.CONTENT_TYPE)) + : null; + } - headers.putAll(this.headers); - headers.putAll(userMetadata); + public Http.Headers makeHeaders() { + return makeHeaders(null, null); + } - if (sse != null) { - headers.putAll(Multimaps.forMap(sse.headers())); - } + public Http.Headers makeHeaders(MediaType contentType, Http.Headers checksumHeaders) { + Http.Headers headers = + Http.Headers.merge( + this.headers, userMetadata, sse == null ? null : sse.headers(), checksumHeaders); String tagging = tags.get().entrySet().stream() - .map(e -> S3Escaper.encode(e.getKey()) + "=" + S3Escaper.encode(e.getValue())) + .map(e -> Utils.encode(e.getKey()) + "=" + Utils.encode(e.getValue())) .collect(Collectors.joining("&")); - if (!tagging.isEmpty()) { - headers.put("x-amz-tagging", tagging); - } + if (!tagging.isEmpty()) headers.put("x-amz-tagging", tagging); if (retention != null && retention.mode() != null) { - headers.put("x-amz-object-lock-mode", retention.mode().name()); + headers.put("x-amz-object-lock-mode", retention.mode().toString()); headers.put( "x-amz-object-lock-retain-until-date", - retention.retainUntilDate().format(Time.RESPONSE_DATE_FORMAT)); + retention.retainUntilDate().format(Time.ISO8601UTC_FORMAT)); } - if (legalHold) { - headers.put("x-amz-object-lock-legal-hold", "ON"); - } + if (legalHold) headers.put("x-amz-object-lock-legal-hold", "ON"); + if (contentType != null) headers.put(Http.Headers.CONTENT_TYPE, contentType.toString()); return headers; } - protected void validateSse(HttpUrl url) { - checkSse(sse, url); + protected void validateSse(boolean isHttps) { + checkSse(sse, isHttps); } - /** Base argument builder class for {@link ObjectWriteArgs}. */ + /** Builder of {@link ObjectWriteArgs}. */ @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class public abstract static class Builder, A extends ObjectWriteArgs> extends ObjectArgs.Builder { public B headers(Map headers) { - final Multimap headersCopy = toMultimap(headers); - operations.add(args -> args.headers = headersCopy); - return (B) this; + return headers(new Http.Headers(headers)); } - public B headers(Multimap headers) { - final Multimap headersCopy = copyMultimap(headers); - operations.add(args -> args.headers = headersCopy); + public B headers(Http.Headers headers) { + final Http.Headers finalHeaders = new Http.Headers(headers); + operations.add(args -> args.headers = finalHeaders); return (B) this; } public B userMetadata(Map userMetadata) { - return userMetadata((userMetadata == null) ? null : Multimaps.forMap(userMetadata)); + return userMetadata(new Http.Headers(userMetadata)); } - public B userMetadata(Multimap userMetadata) { - Multimap userMetadataCopy = HashMultimap.create(); + public B userMetadata(Http.Headers userMetadata) { + Http.Headers normalizedHeaders = new Http.Headers(); if (userMetadata != null) { for (String key : userMetadata.keySet()) { - userMetadataCopy.putAll( + normalizedHeaders.putAll( (key.toLowerCase(Locale.US).startsWith("x-amz-meta-") ? "" : "x-amz-meta-") + key, userMetadata.get(key)); } } - final Multimap finalUserMetadata = - Multimaps.unmodifiableMultimap(userMetadataCopy); + final Http.Headers finalUserMetadata = normalizedHeaders; operations.add(args -> args.userMetadata = finalUserMetadata); return (B) this; } diff --git a/api/src/main/java/io/minio/ObjectWriteResponse.java b/api/src/main/java/io/minio/ObjectWriteResponse.java index 43ece549d..6af1f5cdb 100644 --- a/api/src/main/java/io/minio/ObjectWriteResponse.java +++ b/api/src/main/java/io/minio/ObjectWriteResponse.java @@ -20,7 +20,12 @@ import io.minio.messages.CopyObjectResult; import okhttp3.Headers; -/** Response class of any APIs doing object creation. */ +/** + * Response of {@link MinioAsyncClient#completeMultipartUpload}, {@link + * MinioAsyncClient#composeObject}, {@link MinioAsyncClient#copyObject}, {@link + * MinioAsyncClient#putObject}, {@link MinioAsyncClient#uploadObject} and {@link + * MinioAsyncClient#uploadSnowballObjects}. + */ public class ObjectWriteResponse extends GenericUploadResponse { private String versionId; diff --git a/api/src/main/java/io/minio/PartReader.java b/api/src/main/java/io/minio/PartReader.java index 9209c4536..8c7632456 100644 --- a/api/src/main/java/io/minio/PartReader.java +++ b/api/src/main/java/io/minio/PartReader.java @@ -1,6 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2021 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,157 +16,153 @@ package io.minio; -import com.google.common.io.BaseEncoding; +import io.minio.errors.MinioException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; +import java.util.Map; import java.util.Objects; import javax.annotation.Nonnull; -/** PartReader reads part data from file or input stream sequentially and returns PartSource. */ -class PartReader { - private static final long CHUNK_SIZE = Integer.MAX_VALUE; +public class PartReader { + byte[] buf16k = new byte[16384]; - private byte[] buf16k = new byte[16384]; // 16KiB buffer for optimization. + RandomAccessFile file; + InputStream stream; + long objectSize; + long partSize; + int partCount; + Map hashers; - private RandomAccessFile file; - private InputStream stream; - - private long objectSize; - private long partSize; - private int partCount; - - private int partNumber; - private long totalDataRead; - - private ByteBufferStream[] buffers; - private byte[] oneByte = null; + long totalBytesRead = 0; + int partNumber = 0; + byte[] oneByte = null; boolean eof; - private PartReader(long objectSize, long partSize, int partCount) { - this.objectSize = objectSize; - this.partSize = partSize; - this.partCount = partCount; - - long bufferCount = partSize / CHUNK_SIZE; - if ((partSize - (bufferCount * CHUNK_SIZE)) > 0) bufferCount++; - if (bufferCount == 0) bufferCount++; - - this.buffers = new ByteBufferStream[(int) bufferCount]; - } - - public PartReader(@Nonnull RandomAccessFile file, long objectSize, long partSize, int partCount) { - this(objectSize, partSize, partCount); + public PartReader( + @Nonnull RandomAccessFile file, + long objectSize, + long partSize, + int partCount, + Checksum.Algorithm... algorithms) + throws MinioException { this.file = Objects.requireNonNull(file, "file must not be null"); - if (this.objectSize < 0) throw new IllegalArgumentException("object size must be provided"); + if (objectSize < 0) throw new IllegalArgumentException("valid object size must be provided"); + if (partCount < 0) throw new IllegalArgumentException("part count must be provided"); + set(objectSize, partSize, partCount, algorithms); } - public PartReader(@Nonnull InputStream stream, long objectSize, long partSize, int partCount) { - this(objectSize, partSize, partCount); + public PartReader( + @Nonnull InputStream stream, + Long objectSize, + long partSize, + int partCount, + Checksum.Algorithm... algorithms) + throws MinioException { this.stream = Objects.requireNonNull(stream, "stream must not be null"); - for (int i = 0; i < this.buffers.length; i++) this.buffers[i] = new ByteBufferStream(); + if (partCount == -1) { + objectSize = -1L; + } else if (objectSize < 0) { + throw new IllegalArgumentException("object size must be provided for part count"); + } + set(objectSize, partSize, partCount, algorithms); } - private long readStreamChunk(ByteBufferStream buffer, long size, MessageDigest sha256) - throws IOException { - long totalBytesRead = 0; + private void set(Long objectSize, long partSize, int partCount, Checksum.Algorithm[] algorithms) + throws MinioException { + if (partCount == 0) partCount = -1; + this.objectSize = objectSize == null ? -1 : objectSize; + this.partSize = partSize; + this.partCount = partCount; + this.hashers = Checksum.newHasherMap(algorithms); + } - if (this.oneByte != null) { - buffer.write(this.oneByte); - sha256.update(this.oneByte); - totalBytesRead++; - this.oneByte = null; + private int readBuf16k(int length) throws MinioException { + try { + return file != null ? file.read(buf16k, 0, length) : stream.read(buf16k, 0, length); + } catch (IOException e) { + throw new MinioException(e); } + } - while (totalBytesRead < size) { - long bytesToRead = size - totalBytesRead; - if (bytesToRead > this.buf16k.length) bytesToRead = this.buf16k.length; - int bytesRead = this.stream.read(this.buf16k, 0, (int) bytesToRead); - this.eof = (bytesRead < 0); - if (this.eof) { - if (this.objectSize < 0) break; - throw new IOException("unexpected EOF"); - } - buffer.write(this.buf16k, 0, bytesRead); - sha256.update(this.buf16k, 0, bytesRead); - totalBytesRead += bytesRead; + private void readOneByte() throws MinioException { + if (eof) return; + + oneByte = new byte[] {0}; + int n = 0; + + try { + while ((n = file != null ? file.read(oneByte) : stream.read(oneByte)) == 0) ; + } catch (IOException e) { + throw new MinioException(e); } - return totalBytesRead; + if ((eof = n < 0)) oneByte = null; } - private long readStream(long size, MessageDigest sha256) throws IOException { - long count = size / CHUNK_SIZE; - long lastChunkSize = size - (count * CHUNK_SIZE); - if (lastChunkSize > 0) { - count++; - } else { - lastChunkSize = CHUNK_SIZE; - } + public void read(ByteBuffer buffer) throws MinioException { + if (buffer == null) throw new IllegalArgumentException("valid buffer must be provided"); + if (eof) throw new MinioException("EOF reached"); + if (partNumber == partCount) throw new MinioException("data fully read"); - long totalBytesRead = 0; - for (int i = 0; i < buffers.length; i++) buffers[i].reset(); - for (long i = 1; i <= count && !this.eof; i++) { - long chunkSize = (i != count) ? CHUNK_SIZE : lastChunkSize; - long bytesRead = this.readStreamChunk(buffers[(int) (i - 1)], chunkSize, sha256); - totalBytesRead += bytesRead; + long size = partSize; + if (partCount == 1) { + size = objectSize; + } else if (partNumber == partCount - 1) { + size = objectSize - totalBytesRead; + } + if (buffer.size() < size) { + throw new IllegalArgumentException( + "insufficient buffer size " + buffer.size() + " for data size " + size); } - if (!this.eof && this.objectSize < 0) { - this.oneByte = new byte[1]; - this.eof = this.stream.read(this.oneByte) < 0; + for (Map.Entry entry : hashers.entrySet()) { + entry.getValue().reset(); } - return totalBytesRead; - } + long bytesRead = 0; - private long readFile(long size, MessageDigest sha256) throws IOException { - long position = this.file.getFilePointer(); - long totalBytesRead = 0; - - while (totalBytesRead < size) { - long bytesToRead = size - totalBytesRead; - if (bytesToRead > this.buf16k.length) bytesToRead = this.buf16k.length; - int bytesRead = this.file.read(this.buf16k, 0, (int) bytesToRead); - if (bytesRead < 0) throw new IOException("unexpected EOF"); - sha256.update(this.buf16k, 0, bytesRead); - totalBytesRead += bytesRead; + if (oneByte != null) { + try { + buffer.write(oneByte); + } catch (IOException e) { + throw new MinioException(e); + } + Checksum.update(hashers, oneByte, oneByte.length); + bytesRead++; + oneByte = null; } - this.file.seek(position); - return totalBytesRead; - } + while (bytesRead < size) { + int n = readBuf16k((int) Math.min(size - bytesRead, this.buf16k.length)); + if ((eof = n < 0)) { + if (partCount < 0) break; + throw new MinioException("unexpected EOF"); + } + try { + buffer.write(this.buf16k, 0, n); + } catch (IOException e) { + throw new MinioException(e); + } + Checksum.update(hashers, this.buf16k, n); + bytesRead += n; + } - private long read(long size, MessageDigest sha256) throws IOException { - return (this.file != null) ? readFile(size, sha256) : readStream(size, sha256); + totalBytesRead += bytesRead; + partNumber++; + readOneByte(); + if (eof && partCount < 0) partCount = partNumber; } - public PartSource getPart() throws NoSuchAlgorithmException, IOException { - if (this.partNumber == this.partCount) return null; - - this.partNumber++; - - MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); - - long partSize = this.partSize; - if (this.partNumber == this.partCount) partSize = this.objectSize - this.totalDataRead; - long bytesRead = this.read(partSize, sha256); - this.totalDataRead += bytesRead; - if (this.objectSize < 0 && this.eof) this.partCount = this.partNumber; - - String sha256Hash = BaseEncoding.base16().encode(sha256.digest()).toLowerCase(Locale.US); - - if (this.file != null) { - return new PartSource(this.partNumber, this.file, bytesRead, null, sha256Hash); - } + public Map hashers() { + return hashers; + } - return new PartSource(this.partNumber, this.buffers, bytesRead, null, sha256Hash); + public int partNumber() { + return partNumber; } public int partCount() { - return this.partCount; + return partCount; } } diff --git a/api/src/main/java/io/minio/PartSource.java b/api/src/main/java/io/minio/PartSource.java deleted file mode 100644 index b18581eb5..000000000 --- a/api/src/main/java/io/minio/PartSource.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2021 MinIO, 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 io.minio; - -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.io.SequenceInputStream; -import java.nio.channels.Channels; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import javax.annotation.Nonnull; -import okio.Okio; -import okio.Source; - -/** Part source information. */ -class PartSource { - private int partNumber; - private long size; - private String md5Hash; - private String sha256Hash; - - private RandomAccessFile file; - private long position; - - private ByteBufferStream[] buffers; - - private InputStream inputStream; - - private PartSource(int partNumber, long size, String md5Hash, String sha256Hash) { - this.partNumber = partNumber; - this.size = size; - this.md5Hash = md5Hash; - this.sha256Hash = sha256Hash; - } - - public PartSource( - int partNumber, @Nonnull RandomAccessFile file, long size, String md5Hash, String sha256Hash) - throws IOException { - this(partNumber, size, md5Hash, sha256Hash); - this.file = Objects.requireNonNull(file, "file must not be null"); - this.position = this.file.getFilePointer(); - } - - public PartSource( - int partNumber, - @Nonnull ByteBufferStream[] buffers, - long size, - String md5Hash, - String sha256Hash) { - this(partNumber, size, md5Hash, sha256Hash); - this.buffers = Objects.requireNonNull(buffers, "buffers must not be null"); - } - - public PartSource(@Nonnull InputStream inputStream, long size) { - this(0, size, null, null); - this.inputStream = Objects.requireNonNull(inputStream, "input stream must not be null"); - } - - public int partNumber() { - return this.partNumber; - } - - public long size() { - return this.size; - } - - public String md5Hash() { - return this.md5Hash; - } - - public String sha256Hash() { - return this.sha256Hash; - } - - public Source source() throws IOException { - if (this.file != null) { - this.file.seek(this.position); - return Okio.source(Channels.newInputStream(this.file.getChannel())); - } - - if (this.inputStream != null) { - return Okio.source(this.inputStream); - } - - InputStream stream = buffers[0].inputStream(); - if (buffers.length == 1) return Okio.source(stream); - - List streams = new ArrayList<>(); - streams.add(stream); - for (int i = 1; i < buffers.length; i++) { - if (buffers[i].size() == 0) break; - streams.add(buffers[i].inputStream()); - } - if (streams.size() == 1) return Okio.source(stream); - return Okio.source(new SequenceInputStream(Collections.enumeration(streams))); - } -} diff --git a/api/src/main/java/io/minio/PostPolicy.java b/api/src/main/java/io/minio/PostPolicy.java index 204d06a30..600865454 100644 --- a/api/src/main/java/io/minio/PostPolicy.java +++ b/api/src/main/java/io/minio/PostPolicy.java @@ -19,9 +19,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.minio.credentials.Credentials; +import io.minio.errors.MinioException; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Base64; @@ -29,6 +28,7 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import javax.annotation.Nonnull; @@ -44,7 +44,7 @@ public class PostPolicy { "bucket", "x-amz-algorithm", "x-amz-credential", - "x-amz-date", + Http.Headers.X_AMZ_DATE.toLowerCase(Locale.US), "policy", "x-amz-signature" }); @@ -173,7 +173,7 @@ public void removeContentLengthRangeCondition() { * x-amz-credential, x-amz-security-token, x-amz-date, policy and x-amz-signature. */ public Map formData(@Nonnull Credentials creds, @Nonnull String region) - throws NoSuchAlgorithmException, InvalidKeyException { + throws MinioException { if (creds == null) { throw new IllegalArgumentException("credentials cannot be null"); } @@ -187,7 +187,7 @@ public Map formData(@Nonnull Credentials creds, @Nonnull String } Map policyMap = new HashMap<>(); - policyMap.put("expiration", expiration.format(Time.EXPIRATION_DATE_FORMAT)); + policyMap.put("expiration", expiration.format(Time.ISO8601UTC_FORMAT)); List> conditionList = new LinkedList<>(); conditionList.add(Arrays.asList(new Object[] {"eq", "$bucket", bucketName})); for (Map.Entry> condition : conditions.entrySet()) { @@ -228,9 +228,9 @@ public Map formData(@Nonnull Credentials creds, @Nonnull String formData.put("x-amz-algorithm", ALGORITHM); formData.put("x-amz-credential", credential); if (creds.sessionToken() != null) { - formData.put("x-amz-security-token", creds.sessionToken()); + formData.put(Http.Headers.X_AMZ_SECURITY_TOKEN, creds.sessionToken()); } - formData.put("x-amz-date", amzDate); + formData.put(Http.Headers.X_AMZ_DATE, amzDate); formData.put("policy", policy); formData.put("x-amz-signature", signature); return formData; diff --git a/api/src/main/java/io/minio/PromptObjectArgs.java b/api/src/main/java/io/minio/PromptObjectArgs.java index f092f4c65..faba9113f 100644 --- a/api/src/main/java/io/minio/PromptObjectArgs.java +++ b/api/src/main/java/io/minio/PromptObjectArgs.java @@ -19,7 +19,7 @@ import java.util.Map; import java.util.Objects; -/** Argument class of {@link MinioAsyncClient#promptObject} and {@link MinioClient#promptObject}. */ +/** Arguments of {@link MinioAsyncClient#promptObject} and {@link MinioClient#promptObject}. */ public class PromptObjectArgs extends ObjectArgs { private String prompt; private String lambdaArn; @@ -46,30 +46,30 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link PromptObjectArgs}. */ + /** Builder of {@link PromptObjectArgs}. */ public static final class Builder extends ObjectArgs.Builder { @Override protected void validate(PromptObjectArgs args) { super.validate(args); - validateNotEmptyString(args.prompt, "prompt"); - validateNotEmptyString(args.lambdaArn, "lambda ARN"); - validateNotNull(args.promptArgs, "prompt argument"); + Utils.validateNotEmptyString(args.prompt, "prompt"); + Utils.validateNotEmptyString(args.lambdaArn, "lambda ARN"); + Utils.validateNotNull(args.promptArgs, "prompt argument"); } public Builder offset(String prompt) { - validateNotEmptyString(prompt, "prompt"); + Utils.validateNotEmptyString(prompt, "prompt"); operations.add(args -> args.prompt = prompt); return this; } public Builder lambdaArn(String lambdaArn) { - validateNotEmptyString(lambdaArn, "lambda ARN"); + Utils.validateNotEmptyString(lambdaArn, "lambda ARN"); operations.add(args -> args.lambdaArn = lambdaArn); return this; } public Builder promptArgs(Map promptArgs) { - validateNotNull(promptArgs, "prompt argument"); + Utils.validateNotNull(promptArgs, "prompt argument"); operations.add(args -> args.promptArgs = promptArgs); return this; } diff --git a/api/src/main/java/io/minio/PromptObjectResponse.java b/api/src/main/java/io/minio/PromptObjectResponse.java index 0d501850b..38234f2f8 100644 --- a/api/src/main/java/io/minio/PromptObjectResponse.java +++ b/api/src/main/java/io/minio/PromptObjectResponse.java @@ -21,9 +21,9 @@ import okhttp3.Headers; /** - * Response class of {@link MinioAsyncClient#promptObject} and {@link MinioClient#promptObject}. - * This class is {@link InputStream} interface compatible and it must be closed after use to release - * underneath network resources. + * Response of {@link MinioAsyncClient#promptObject} and {@link MinioClient#promptObject}. As it is + * {@link InputStream} interface compatible, it must be closed after use to release underneath + * network resources. */ public class PromptObjectResponse extends FilterInputStream { private GenericResponse response; diff --git a/api/src/main/java/io/minio/PutObjectAPIArgs.java b/api/src/main/java/io/minio/PutObjectAPIArgs.java new file mode 100644 index 000000000..8c896b929 --- /dev/null +++ b/api/src/main/java/io/minio/PutObjectAPIArgs.java @@ -0,0 +1,106 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.io.RandomAccessFile; +import java.util.Objects; +import okhttp3.MediaType; + +/** Arguments of {@link BaseS3Client#putObject}. */ +public class PutObjectAPIArgs extends PutObjectAPIBaseArgs { + private MediaType contentType; + + protected PutObjectAPIArgs() {} + + public PutObjectAPIArgs( + PutObjectBaseArgs args, + ByteBuffer buffer, + MediaType contentType, + Http.Headers checksumHeaders) { + super(args, buffer, args.makeHeaders(contentType, checksumHeaders)); + this.contentType = contentType; + } + + public PutObjectAPIArgs( + PutObjectBaseArgs args, + RandomAccessFile file, + long length, + MediaType contentType, + Http.Headers checksumHeaders) { + super(args, file, length, args.makeHeaders(contentType, checksumHeaders)); + this.contentType = contentType; + } + + public PutObjectAPIArgs( + PutObjectBaseArgs args, + byte[] data, + int length, + MediaType contentType, + Http.Headers checksumHeaders) { + super(args, data, length, args.makeHeaders(contentType, checksumHeaders)); + this.contentType = contentType; + } + + public PutObjectAPIArgs( + UploadSnowballObjectsArgs args, byte[] data, int length, Http.Headers headers) { + super(args, data, length, headers); + } + + public PutObjectAPIArgs( + UploadSnowballObjectsArgs args, RandomAccessFile file, long length, Http.Headers headers) { + super(args, file, length, headers); + } + + public MediaType contentType() { + return contentType; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link PutObjectAPIArgs}. */ + public static final class Builder + extends PutObjectAPIBaseArgs.Builder { + public Builder contentType(String value) { + MediaType contentType = MediaType.parse(value); + if (value != null && contentType == null) { + throw new IllegalArgumentException("invalid content type '" + value + "' as per RFC 2045"); + } + return contentType(contentType); + } + + public Builder contentType(MediaType contentType) { + operations.add(args -> args.contentType = contentType); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PutObjectAPIArgs)) return false; + if (!super.equals(o)) return false; + PutObjectAPIArgs that = (PutObjectAPIArgs) o; + return Objects.equals(contentType, that.contentType); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), contentType); + } +} diff --git a/api/src/main/java/io/minio/PutObjectAPIBaseArgs.java b/api/src/main/java/io/minio/PutObjectAPIBaseArgs.java new file mode 100644 index 000000000..50563674f --- /dev/null +++ b/api/src/main/java/io/minio/PutObjectAPIBaseArgs.java @@ -0,0 +1,153 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.io.RandomAccessFile; +import java.util.Arrays; +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#putObject}. */ +public abstract class PutObjectAPIBaseArgs extends ObjectArgs { + protected RandomAccessFile file; + protected ByteBuffer buffer; + protected byte[] data; + protected Long length; + protected Http.Headers headers; + + protected PutObjectAPIBaseArgs() {} + + private PutObjectAPIBaseArgs(PutObjectBaseArgs args, Http.Headers headers) { + super(args); + this.headers = headers; + } + + protected PutObjectAPIBaseArgs(PutObjectBaseArgs args, ByteBuffer buffer, Http.Headers headers) { + this(args, headers); + this.buffer = buffer; + } + + protected PutObjectAPIBaseArgs( + PutObjectBaseArgs args, RandomAccessFile file, long length, Http.Headers headers) { + this(args, headers); + this.file = file; + this.length = length; + } + + protected PutObjectAPIBaseArgs( + PutObjectBaseArgs args, byte[] data, int length, Http.Headers headers) { + this(args, headers); + this.data = data; + this.length = (long) length; + } + + protected PutObjectAPIBaseArgs( + UploadSnowballObjectsArgs args, byte[] data, int length, Http.Headers headers) { + super(args); + this.data = data; + this.length = (long) length; + this.headers = headers; + } + + protected PutObjectAPIBaseArgs( + UploadSnowballObjectsArgs args, RandomAccessFile file, long length, Http.Headers headers) { + super(args); + this.file = file; + this.length = length; + this.headers = headers; + } + + public RandomAccessFile file() { + return file; + } + + public ByteBuffer buffer() { + return buffer; + } + + public byte[] data() { + return data; + } + + public Long length() { + return length; + } + + public Http.Headers headers() { + return headers; + } + + /** Base argument builder of {@link PutObjectAPIBaseArgs}. */ + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public abstract static class Builder, A extends PutObjectAPIBaseArgs> + extends ObjectArgs.Builder { + protected void validate(A args) { + super.validate(args); + if (!((args.file != null) != (args.buffer != null) != (args.data != null) + && !(args.file != null && args.buffer != null && args.data != null))) { + throw new IllegalArgumentException("only one of file, buffer or data must be provided"); + } + } + + public B setData(RandomAccessFile file, ByteBuffer buffer, byte[] data, Long length) { + operations.add(args -> args.file = file); + operations.add(args -> args.buffer = buffer); + operations.add(args -> args.data = data); + operations.add(args -> args.length = length); + return (B) this; + } + + public B file(RandomAccessFile file, long length) { + Utils.validateNotNull(file, "file"); + if (length < 0) throw new IllegalArgumentException("valid length must be provided"); + return setData(file, null, null, length); + } + + public B buffer(ByteBuffer buffer) { + Utils.validateNotNull(buffer, "buffer"); + return setData(null, buffer, null, null); + } + + public B data(byte[] data, int length) { + Utils.validateNotNull(data, "data"); + if (length < 0) throw new IllegalArgumentException("valid length must be provided"); + return setData(null, null, data, (long) length); + } + + public B headers(Http.Headers headers) { + operations.add(args -> args.headers = headers); + return (B) this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PutObjectAPIBaseArgs)) return false; + if (!super.equals(o)) return false; + PutObjectAPIBaseArgs that = (PutObjectAPIBaseArgs) o; + return Objects.equals(file, that.file) + && Objects.equals(buffer, that.buffer) + && Arrays.equals(data, that.data) + && Objects.equals(length, that.length) + && Objects.equals(headers, that.headers); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), file, buffer, data, length, headers); + } +} diff --git a/api/src/main/java/io/minio/PutObjectArgs.java b/api/src/main/java/io/minio/PutObjectArgs.java index bdc2f5869..b29a2784c 100644 --- a/api/src/main/java/io/minio/PutObjectArgs.java +++ b/api/src/main/java/io/minio/PutObjectArgs.java @@ -16,79 +16,79 @@ package io.minio; -import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Objects; +import okhttp3.MediaType; -/** Argument class of {@link MinioAsyncClient#putObject} and {@link MinioClient#putObject}. */ +/** Arguments of {@link MinioAsyncClient#putObject} and {@link MinioClient#putObject}. */ public class PutObjectArgs extends PutObjectBaseArgs { - private BufferedInputStream stream; + private InputStream stream; + private byte[] data; - public BufferedInputStream stream() { + public InputStream stream() { return stream; } - /** - * Gets content type. It returns if content type is set (or) value of "Content-Type" header (or) - * default "application/octet-stream". - */ - public String contentType() throws IOException { - String contentType = super.contentType(); - return (contentType != null) ? contentType : "application/octet-stream"; + public byte[] data() { + return data; + } + + public MediaType contentType() throws IOException { + return super.contentType(); } public static Builder builder() { return new Builder(); } - /** Argument builder of {@link PutObjectArgs}. */ + /** Builder of {@link PutObjectArgs}. */ public static final class Builder extends PutObjectBaseArgs.Builder { @Override protected void validate(PutObjectArgs args) { super.validate(args); - validateNotNull(args.stream, "stream"); + if (args.stream == null && args.data == null) { + throw new IllegalArgumentException("either stream or data must be provided"); + } + } + + private Builder setStream( + InputStream stream, byte[] data, Long objectSize, long partSize, int partCount) { + operations.add(args -> args.stream = stream); + operations.add(args -> args.data = data); + operations.add(args -> args.objectSize = objectSize); + operations.add(args -> args.partSize = partSize); + operations.add(args -> args.partCount = partCount); + return this; } /** * Sets stream to upload. Two ways to provide object/part sizes. * *
    - *
  • If object size is unknown, pass -1 to objectSize and pass valid partSize. - *
  • If object size is known, pass -1 to partSize for auto detect; else pass valid partSize - * to control memory usage and no. of parts in upload. - *
  • If partSize is greater than objectSize, objectSize is used as partSize. + *
  • If object size is unknown, pass valid part size. + *
  • If object size is known, pass valid part size to control memory usage and no. of parts + * to upload. *
* *

A valid part size is between 5MiB to 5GiB (both limits inclusive). */ - public Builder stream(InputStream stream, long objectSize, long partSize) { - validateNotNull(stream, "stream"); - + public Builder stream(InputStream stream, Long objectSize, Long partSize) { + Utils.validateNotNull(stream, "stream"); long[] partinfo = getPartInfo(objectSize, partSize); - long pSize = partinfo[0]; - int pCount = (int) partinfo[1]; - - final BufferedInputStream bis = - (stream instanceof BufferedInputStream) - ? (BufferedInputStream) stream - : new BufferedInputStream(stream); - return setStream(bis, objectSize, pSize, pCount); - } - - private Builder setStream( - BufferedInputStream stream, long objectSize, long partSize, int partCount) { - operations.add(args -> args.stream = stream); - operations.add(args -> args.objectSize = objectSize); - operations.add(args -> args.partSize = partSize); - operations.add(args -> args.partCount = partCount); - return this; + return setStream(stream, null, objectSize, partinfo[0], (int) partinfo[1]); } - public Builder contentType(String contentType) { - validateContentType(contentType); - operations.add(args -> args.contentType = contentType); - return this; + public Builder data(byte[] data, int length) { + if (data != null && length < 0) { + throw new IllegalArgumentException("valid length must be provided"); + } + return setStream( + null, + data, + data == null ? null : (long) length, + (long) Math.max(MIN_MULTIPART_SIZE, data == null ? -1 : length), + 1); } } diff --git a/api/src/main/java/io/minio/PutObjectBaseArgs.java b/api/src/main/java/io/minio/PutObjectBaseArgs.java index aaec5e1bb..7ec3c9dd9 100644 --- a/api/src/main/java/io/minio/PutObjectBaseArgs.java +++ b/api/src/main/java/io/minio/PutObjectBaseArgs.java @@ -20,15 +20,16 @@ import java.util.Objects; import okhttp3.MediaType; -/** Base argument class for {@link PutObjectArgs} and {@link UploadObjectArgs}. */ +/** Common arguments of {@link PutObjectArgs} and {@link UploadObjectArgs}. */ public abstract class PutObjectBaseArgs extends ObjectWriteArgs { - protected long objectSize; + protected Long objectSize; protected long partSize; protected int partCount; - protected String contentType; - protected boolean preloadData; + protected MediaType contentType; + protected Checksum.Algorithm checksum; + protected int parallelUploads; - public long objectSize() { + public Long objectSize() { return objectSize; } @@ -40,37 +41,35 @@ public int partCount() { return partCount; } - /** Gets content type. It returns if content type is set (or) value of "Content-Type" header. */ - public String contentType() throws IOException { - if (contentType != null) { - return contentType; - } - - if (this.headers().containsKey("Content-Type")) { - return this.headers().get("Content-Type").iterator().next(); - } + public MediaType contentType() throws IOException { + return contentType != null ? contentType : super.contentType(); + } - return null; + public Checksum.Algorithm checksum() { + return checksum; } - public boolean preloadData() { - return preloadData; + public int parallelUploads() { + return parallelUploads; } - /** Base argument builder class for {@link PutObjectBaseArgs}. */ + /** Builder of {@link PutObjectBaseArgs}. */ @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class public abstract static class Builder, A extends PutObjectBaseArgs> extends ObjectWriteArgs.Builder { - protected void validateContentType(String contentType) { - validateNotEmptyString(contentType, "content type"); - if (MediaType.parse(contentType) == null) { + protected void validate(A args) { + super.validate(args); + if (args.checksum != null + && args.partCount > 0 + && (!(args.partCount == 1 && args.checksum.fullObjectSupport() + || args.partCount > 1 && args.checksum.compositeSupport()))) { throw new IllegalArgumentException( - "invalid content type '" + contentType + "' as per RFC 2045"); + "unsupported checksum " + args.checksum + " for part count " + args.partCount); } } - private void validateSizes(long objectSize, long partSize) { - if (partSize > 0) { + protected long[] getPartInfo(Long objectSize, Long partSize) { + if (partSize != null && partSize > 0) { if (partSize < MIN_MULTIPART_SIZE) { throw new IllegalArgumentException( "part size " + partSize + " is not supported; minimum allowed 5MiB"); @@ -82,31 +81,24 @@ private void validateSizes(long objectSize, long partSize) { } } - if (objectSize >= 0) { - if (objectSize > MAX_OBJECT_SIZE) { + if (objectSize == null || objectSize < 0) { + if (partSize == null || partSize <= 0) { throw new IllegalArgumentException( - "object size " + objectSize + " is not supported; maximum allowed 5TiB"); + "valid part size must be provided for unknown object size"); } - } else if (partSize <= 0) { - throw new IllegalArgumentException( - "valid part size must be provided when object size is unknown"); + return new long[] {partSize, -1}; } - } - - protected long[] getPartInfo(long objectSize, long partSize) { - validateSizes(objectSize, partSize); - - if (objectSize < 0) return new long[] {partSize, -1}; - if (partSize <= 0) { + if (partSize == null || partSize <= 0) { // Calculate part size by multiple of MIN_MULTIPART_SIZE. double dPartSize = Math.ceil((double) objectSize / MAX_MULTIPART_COUNT); dPartSize = Math.ceil(dPartSize / MIN_MULTIPART_SIZE) * MIN_MULTIPART_SIZE; partSize = (long) dPartSize; } - if (partSize > objectSize) partSize = objectSize; - long partCount = partSize > 0 ? (long) Math.ceil((double) objectSize / partSize) : 1; + if (partSize > objectSize) return new long[] {partSize, 1}; + + long partCount = (long) Math.ceil((double) objectSize / partSize); if (partCount > MAX_MULTIPART_COUNT) { throw new IllegalArgumentException( "object size " @@ -121,16 +113,29 @@ protected long[] getPartInfo(long objectSize, long partSize) { return new long[] {partSize, partCount}; } - /** - * Sets flag to control data preload of stream/file. When this flag is enabled, entire - * part/object data is loaded into memory to enable connection retry on network failure in the - * middle of upload. - * - * @deprecated As this behavior is enabled by default and cannot be turned off. - */ - @Deprecated - public B preloadData(boolean preloadData) { - operations.add(args -> args.preloadData = preloadData); + public B contentType(String value) { + MediaType contentType = MediaType.parse(value); + if (value != null && contentType == null) { + throw new IllegalArgumentException("invalid content type '" + value + "' as per RFC 2045"); + } + return contentType(contentType); + } + + public B contentType(MediaType contentType) { + operations.add(args -> args.contentType = contentType); + return (B) this; + } + + public B checksum(Checksum.Algorithm algorithm) { + if (algorithm == Checksum.Algorithm.MD5) { + throw new IllegalArgumentException(Checksum.Algorithm.MD5 + " algorithm is not allowed"); + } + operations.add(args -> args.checksum = algorithm); + return (B) this; + } + + public B parallelUploads(int parallelUploads) { + operations.add(args -> args.parallelUploads = parallelUploads); return (B) this; } } @@ -141,16 +146,17 @@ public boolean equals(Object o) { if (!(o instanceof PutObjectBaseArgs)) return false; if (!super.equals(o)) return false; PutObjectBaseArgs that = (PutObjectBaseArgs) o; - return objectSize == that.objectSize + return Objects.equals(objectSize, that.objectSize) && partSize == that.partSize && partCount == that.partCount && Objects.equals(contentType, that.contentType) - && preloadData == that.preloadData; + && Objects.equals(checksum, that.checksum) + && parallelUploads == that.parallelUploads; } @Override public int hashCode() { return Objects.hash( - super.hashCode(), objectSize, partSize, partCount, contentType, preloadData); + super.hashCode(), objectSize, partSize, partCount, contentType, checksum, parallelUploads); } } diff --git a/api/src/main/java/io/minio/PutObjectFanOutArgs.java b/api/src/main/java/io/minio/PutObjectFanOutArgs.java index 64ad1cb60..976f518fb 100644 --- a/api/src/main/java/io/minio/PutObjectFanOutArgs.java +++ b/api/src/main/java/io/minio/PutObjectFanOutArgs.java @@ -25,11 +25,9 @@ import java.io.InputStream; import java.util.List; import java.util.Objects; -import okhttp3.HttpUrl; /** - * Argument class of {@link MinioAsyncClient#putObjectFanOut} and {@link - * MinioClient#putObjectFanOut}. + * Arguments of {@link MinioAsyncClient#putObjectFanOut} and {@link MinioClient#putObjectFanOut}. */ public class PutObjectFanOutArgs extends BucketArgs { private static final ObjectMapper objectMapper = @@ -74,25 +72,25 @@ public String fanOutList() throws JsonProcessingException { return builder.toString(); } - public void validateSse(HttpUrl url) { - checkSse(sse, url); + public void validateSse(boolean isHttps) { + checkSse(sse, isHttps); } public static Builder builder() { return new Builder(); } - /** Argument builder of {@link PutObjectFanOutArgs}. */ + /** Builder of {@link PutObjectFanOutArgs}. */ public static final class Builder extends BucketArgs.Builder { @Override protected void validate(PutObjectFanOutArgs args) { super.validate(args); - validateNotNull(args.stream, "stream"); - validateNotNull(args.entries, "fan-out entries"); + Utils.validateNotNull(args.stream, "stream"); + Utils.validateNotNull(args.entries, "fan-out entries"); } public Builder stream(InputStream stream, long size) { - validateNotNull(stream, "stream"); + Utils.validateNotNull(stream, "stream"); if (size < 0) { throw new IllegalArgumentException("invalid stream size " + size); } diff --git a/api/src/main/java/io/minio/PutObjectFanOutEntry.java b/api/src/main/java/io/minio/PutObjectFanOutEntry.java index 9bf029b97..ac9614707 100644 --- a/api/src/main/java/io/minio/PutObjectFanOutEntry.java +++ b/api/src/main/java/io/minio/PutObjectFanOutEntry.java @@ -67,11 +67,11 @@ public static Builder builder() { public static final class Builder extends BaseArgs.Builder { @Override protected void validate(PutObjectFanOutEntry args) { - validateNotEmptyString(args.key, "key"); + Utils.validateNotEmptyString(args.key, "key"); } public Builder key(String key) { - validateNotEmptyString(key, "key"); + Utils.validateNotEmptyString(key, "key"); operations.add(args -> args.key = key); return this; } diff --git a/api/src/main/java/io/minio/PutObjectFanOutResponse.java b/api/src/main/java/io/minio/PutObjectFanOutResponse.java index e1f28be06..493e6ca38 100644 --- a/api/src/main/java/io/minio/PutObjectFanOutResponse.java +++ b/api/src/main/java/io/minio/PutObjectFanOutResponse.java @@ -17,13 +17,11 @@ package io.minio; import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.ZonedDateTime; import java.util.List; import okhttp3.Headers; -/** - * Response class of {@link MinioAsyncClient#putObjectFanOut} and {@link - * MinioClient#putObjectFanOut}. - */ +/** Response of {@link MinioAsyncClient#putObjectFanOut} and {@link MinioClient#putObjectFanOut}. */ public class PutObjectFanOutResponse extends GenericUploadResponse { private List results; @@ -48,8 +46,7 @@ public static class Result { private String versionId; @JsonProperty("lastModified") - private String lastModified; - // private ResponseDate lastModified; + private Time.S3Time lastModified; @JsonProperty("error") private String error; @@ -68,8 +65,8 @@ public String versionId() { return versionId; } - public String lastModified() { - return lastModified; + public ZonedDateTime lastModified() { + return lastModified == null ? null : lastModified.toZonedDateTime(); } public String error() { diff --git a/api/src/main/java/io/minio/RemoveBucketArgs.java b/api/src/main/java/io/minio/RemoveBucketArgs.java index 958c3d40a..d7be206ff 100644 --- a/api/src/main/java/io/minio/RemoveBucketArgs.java +++ b/api/src/main/java/io/minio/RemoveBucketArgs.java @@ -16,13 +16,13 @@ package io.minio; -/** Argument class of {@link MinioAsyncClient#removeBucket} and {@link MinioClient#removeBucket}. */ +/** Arguments of {@link MinioAsyncClient#removeBucket} and {@link MinioClient#removeBucket}. */ public class RemoveBucketArgs extends BucketArgs { public static Builder builder() { return new Builder(); } - /** Argument builder of {@link RemoveBucketArgs}. */ + /** Builder of {@link RemoveBucketArgs}. */ public static final class Builder extends BucketArgs.Builder {} } diff --git a/api/src/main/java/io/minio/RemoveObjectArgs.java b/api/src/main/java/io/minio/RemoveObjectArgs.java index b33376118..d62d8b503 100644 --- a/api/src/main/java/io/minio/RemoveObjectArgs.java +++ b/api/src/main/java/io/minio/RemoveObjectArgs.java @@ -18,7 +18,7 @@ import java.util.Objects; -/** Argument class of {@link MinioAsyncClient#removeObject} and {@link MinioClient#removeObject}. */ +/** Arguments of {@link MinioAsyncClient#removeObject} and {@link MinioClient#removeObject}. */ public class RemoveObjectArgs extends ObjectVersionArgs { private boolean bypassGovernanceMode; @@ -30,7 +30,7 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link RemoveObjectArgs}. */ + /** Builder of {@link RemoveObjectArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder { public Builder bypassGovernanceMode(boolean flag) { operations.add(args -> args.bypassGovernanceMode = flag); diff --git a/api/src/main/java/io/minio/RemoveObjectsArgs.java b/api/src/main/java/io/minio/RemoveObjectsArgs.java index a3b678e65..c459b7fd6 100644 --- a/api/src/main/java/io/minio/RemoveObjectsArgs.java +++ b/api/src/main/java/io/minio/RemoveObjectsArgs.java @@ -16,22 +16,20 @@ package io.minio; -import io.minio.messages.DeleteObject; +import io.minio.messages.DeleteRequest; import java.util.LinkedList; import java.util.Objects; -/** - * Argument class of {@link MinioAsyncClient#removeObjects} and {@link MinioClient#removeObjects}. - */ +/** Arguments of {@link MinioAsyncClient#removeObjects} and {@link MinioClient#removeObjects}. */ public class RemoveObjectsArgs extends BucketArgs { private boolean bypassGovernanceMode; - private Iterable objects = new LinkedList<>(); + private Iterable objects = new LinkedList<>(); public boolean bypassGovernanceMode() { return bypassGovernanceMode; } - public Iterable objects() { + public Iterable objects() { return objects; } @@ -39,15 +37,15 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link RemoveObjectsArgs}. */ + /** Builder of {@link RemoveObjectsArgs}. */ public static final class Builder extends BucketArgs.Builder { public Builder bypassGovernanceMode(boolean flag) { operations.add(args -> args.bypassGovernanceMode = flag); return this; } - public Builder objects(Iterable objects) { - validateNotNull(objects, "objects"); + public Builder objects(Iterable objects) { + Utils.validateNotNull(objects, "objects"); operations.add(args -> args.objects = objects); return this; } diff --git a/api/src/main/java/io/minio/RestoreObjectArgs.java b/api/src/main/java/io/minio/RestoreObjectArgs.java index 14467c6e1..771b77aa2 100644 --- a/api/src/main/java/io/minio/RestoreObjectArgs.java +++ b/api/src/main/java/io/minio/RestoreObjectArgs.java @@ -19,7 +19,7 @@ import io.minio.messages.RestoreRequest; import java.util.Objects; -/** Argument class of {@link MinioClient#restoreObject}. */ +/** Arguments of {@link MinioClient#restoreObject}. */ public class RestoreObjectArgs extends ObjectVersionArgs { private RestoreRequest request; @@ -31,10 +31,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link RestoreObjectArgs}. */ + /** Builder of {@link RestoreObjectArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder { private void validateRequest(RestoreRequest request) { - validateNotNull(request, "request"); + Utils.validateNotNull(request, "request"); } public Builder request(RestoreRequest request) { diff --git a/api/src/main/java/io/minio/Result.java b/api/src/main/java/io/minio/Result.java index 0b3b3cc50..bb1df0e74 100644 --- a/api/src/main/java/io/minio/Result.java +++ b/api/src/main/java/io/minio/Result.java @@ -16,91 +16,26 @@ package io.minio; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -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 java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import io.minio.errors.MinioException; -/** A container class keeps any type or an exception. */ +/** A container class keeps any type or a MinioException. */ public class Result { private final T type; - private final Exception ex; + private final MinioException ex; public Result(T type) { this.type = type; this.ex = null; } - public Result(Exception ex) { + public Result(MinioException ex) { this.type = null; this.ex = ex; } - /** Returns given Type if exception is null, else respective exception is thrown. */ - public T get() - throws ErrorResponseException, IllegalArgumentException, InsufficientDataException, - InternalException, InvalidKeyException, InvalidResponseException, IOException, - JsonMappingException, JsonParseException, NoSuchAlgorithmException, ServerException, - XmlParserException { - if (ex == null) { - return type; - } - - if (ex instanceof ErrorResponseException) { - throw (ErrorResponseException) ex; - } - - if (ex instanceof IllegalArgumentException) { - throw (IllegalArgumentException) ex; - } - - if (ex instanceof InsufficientDataException) { - throw (InsufficientDataException) ex; - } - - if (ex instanceof InternalException) { - throw (InternalException) ex; - } - - if (ex instanceof InvalidKeyException) { - throw (InvalidKeyException) ex; - } - - if (ex instanceof InvalidResponseException) { - throw (InvalidResponseException) ex; - } - - if (ex instanceof IOException) { - throw (IOException) ex; - } - - if (ex instanceof JsonMappingException) { - throw (JsonMappingException) ex; - } - - if (ex instanceof JsonParseException) { - throw (JsonParseException) ex; - } - - if (ex instanceof NoSuchAlgorithmException) { - throw (NoSuchAlgorithmException) ex; - } - - if (ex instanceof ServerException) { - throw (ServerException) ex; - } - - if (ex instanceof XmlParserException) { - throw (XmlParserException) ex; - } - - throw new RuntimeException("Exception not handled", ex); + /** Returns given Type if exception is null, else the exception is thrown. */ + public T get() throws MinioException { + if (ex == null) return type; + throw ex; } } diff --git a/api/src/main/java/io/minio/S3Base.java b/api/src/main/java/io/minio/S3Base.java deleted file mode 100644 index 324637ccb..000000000 --- a/api/src/main/java/io/minio/S3Base.java +++ /dev/null @@ -1,3909 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2021 MinIO, 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 io.minio; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.minio.credentials.Credentials; -import io.minio.credentials.Provider; -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 io.minio.http.HttpUtils; -import io.minio.http.Method; -import io.minio.messages.CompleteMultipartUpload; -import io.minio.messages.CompleteMultipartUploadResult; -import io.minio.messages.CopyPartResult; -import io.minio.messages.DeleteError; -import io.minio.messages.DeleteMarker; -import io.minio.messages.DeleteObject; -import io.minio.messages.DeleteRequest; -import io.minio.messages.DeleteResult; -import io.minio.messages.ErrorResponse; -import io.minio.messages.InitiateMultipartUploadResult; -import io.minio.messages.Item; -import io.minio.messages.ListAllMyBucketsResult; -import io.minio.messages.ListBucketResultV1; -import io.minio.messages.ListBucketResultV2; -import io.minio.messages.ListMultipartUploadsResult; -import io.minio.messages.ListObjectsResult; -import io.minio.messages.ListPartsResult; -import io.minio.messages.ListVersionsResult; -import io.minio.messages.LocationConstraint; -import io.minio.messages.NotificationRecords; -import io.minio.messages.Part; -import io.minio.messages.Prefix; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Random; -import java.util.Scanner; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; - -/** Core S3 API client. */ -public abstract class S3Base implements AutoCloseable { - static { - try { - RequestBody.create(new byte[] {}, null); - } catch (NoSuchMethodError ex) { - throw new RuntimeException("Unsupported OkHttp library found. Must use okhttp >= 4.11.0", ex); - } - } - - protected static final String NO_SUCH_BUCKET_MESSAGE = "Bucket does not exist"; - protected static final String NO_SUCH_BUCKET = "NoSuchBucket"; - protected static final String NO_SUCH_BUCKET_POLICY = "NoSuchBucketPolicy"; - protected static final String NO_SUCH_OBJECT_LOCK_CONFIGURATION = "NoSuchObjectLockConfiguration"; - protected static final String SERVER_SIDE_ENCRYPTION_CONFIGURATION_NOT_FOUND_ERROR = - "ServerSideEncryptionConfigurationNotFoundError"; - protected static final long DEFAULT_CONNECTION_TIMEOUT = TimeUnit.MINUTES.toMillis(5); - // maximum allowed bucket policy size is 20KiB - protected static final int MAX_BUCKET_POLICY_SIZE = 20 * 1024; - protected static final String US_EAST_1 = "us-east-1"; - protected final Map regionCache = new ConcurrentHashMap<>(); - protected static final Random random = new Random(new SecureRandom().nextLong()); - protected static final ObjectMapper objectMapper = - JsonMapper.builder() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true) - .build(); - - private static final String RETRY_HEAD = "RetryHead"; - private static final String END_HTTP = "----------END-HTTP----------"; - private static final String UPLOAD_ID = "uploadId"; - private static final Set TRACE_QUERY_PARAMS = - ImmutableSet.of("retention", "legal-hold", "tagging", UPLOAD_ID, "acl", "attributes"); - private PrintWriter traceStream; - private String userAgent = MinioProperties.INSTANCE.getDefaultUserAgent(); - - protected HttpUrl baseUrl; - protected String awsS3Prefix; - protected String awsDomainSuffix; - protected boolean awsDualstack; - protected boolean useVirtualStyle; - protected String region; - protected Provider provider; - protected OkHttpClient httpClient; - protected boolean closeHttpClient; - - /** @deprecated This method is no longer supported. */ - @Deprecated - protected S3Base( - HttpUrl baseUrl, - String awsS3Prefix, - String awsDomainSuffix, - boolean awsDualstack, - boolean useVirtualStyle, - String region, - Provider provider, - OkHttpClient httpClient) { - this( - baseUrl, - awsS3Prefix, - awsDomainSuffix, - awsDualstack, - useVirtualStyle, - region, - provider, - httpClient, - false); - } - - protected S3Base( - HttpUrl baseUrl, - String awsS3Prefix, - String awsDomainSuffix, - boolean awsDualstack, - boolean useVirtualStyle, - String region, - Provider provider, - OkHttpClient httpClient, - boolean closeHttpClient) { - this.baseUrl = baseUrl; - this.awsS3Prefix = awsS3Prefix; - this.awsDomainSuffix = awsDomainSuffix; - this.awsDualstack = awsDualstack; - this.useVirtualStyle = useVirtualStyle; - this.region = region; - this.provider = provider; - this.httpClient = httpClient; - this.closeHttpClient = closeHttpClient; - } - - /** @deprecated This method is no longer supported. */ - @Deprecated - protected S3Base( - HttpUrl baseUrl, - String region, - boolean isAwsHost, - boolean isFipsHost, - boolean isAccelerateHost, - boolean isDualStackHost, - boolean useVirtualStyle, - Provider provider, - OkHttpClient httpClient) { - this.baseUrl = baseUrl; - if (isAwsHost) this.awsS3Prefix = "s3."; - if (isFipsHost) this.awsS3Prefix = "s3-fips."; - if (isAccelerateHost) this.awsS3Prefix = "s3-accelerate."; - if (isAwsHost || isFipsHost || isAccelerateHost) { - String host = baseUrl.host(); - if (host.endsWith(".amazonaws.com")) this.awsDomainSuffix = "amazonaws.com"; - if (host.endsWith(".amazonaws.com.cn")) this.awsDomainSuffix = "amazonaws.com.cn"; - } - this.awsDualstack = isDualStackHost; - this.useVirtualStyle = useVirtualStyle; - this.region = region; - this.provider = provider; - this.httpClient = httpClient; - this.closeHttpClient = false; - } - - protected S3Base(S3Base client) { - this.baseUrl = client.baseUrl; - this.awsS3Prefix = client.awsS3Prefix; - this.awsDomainSuffix = client.awsDomainSuffix; - this.awsDualstack = client.awsDualstack; - this.useVirtualStyle = client.useVirtualStyle; - this.region = client.region; - this.provider = client.provider; - this.httpClient = client.httpClient; - this.closeHttpClient = client.closeHttpClient; - } - - /** Check whether argument is valid or not. */ - protected void checkArgs(BaseArgs args) { - if (args == null) throw new IllegalArgumentException("null arguments"); - - if ((this.awsDomainSuffix != null) && (args instanceof BucketArgs)) { - String bucketName = ((BucketArgs) args).bucket(); - if (bucketName.startsWith("xn--") - || bucketName.endsWith("--s3alias") - || bucketName.endsWith("--ol-s3")) { - throw new IllegalArgumentException( - "bucket name '" - + bucketName - + "' must not start with 'xn--' and must not end with '--s3alias' or '--ol-s3'"); - } - } - } - - /** Merge two Multimaps. */ - protected Multimap merge( - Multimap m1, Multimap m2) { - Multimap map = HashMultimap.create(); - if (m1 != null) map.putAll(m1); - if (m2 != null) map.putAll(m2); - return map; - } - - /** Create new HashMultimap by alternating keys and values. */ - protected Multimap newMultimap(String... keysAndValues) { - if (keysAndValues.length % 2 != 0) { - throw new IllegalArgumentException("Expected alternating keys and values"); - } - - Multimap map = HashMultimap.create(); - for (int i = 0; i < keysAndValues.length; i += 2) { - map.put(keysAndValues[i], keysAndValues[i + 1]); - } - - return map; - } - - /** Create new HashMultimap with copy of Map. */ - protected Multimap newMultimap(Map map) { - return (map != null) ? Multimaps.forMap(map) : HashMultimap.create(); - } - - /** Create new HashMultimap with copy of Multimap. */ - protected Multimap newMultimap(Multimap map) { - return (map != null) ? HashMultimap.create(map) : HashMultimap.create(); - } - - /** Throws encapsulated exception wrapped by {@link ExecutionException}. */ - public void throwEncapsulatedException(ExecutionException e) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - if (e == null) return; - - Throwable ex = e.getCause(); - - if (ex instanceof CompletionException) { - ex = ((CompletionException) ex).getCause(); - } - - if (ex instanceof ExecutionException) { - ex = ((ExecutionException) ex).getCause(); - } - - try { - throw ex; - } catch (IllegalArgumentException - | ErrorResponseException - | InsufficientDataException - | InternalException - | InvalidKeyException - | InvalidResponseException - | IOException - | NoSuchAlgorithmException - | ServerException - | XmlParserException exc) { - throw exc; - } catch (Throwable exc) { - throw new RuntimeException(exc.getCause() == null ? exc : exc.getCause()); - } - } - - private String[] handleRedirectResponse( - Method method, String bucketName, Response response, boolean retry) { - String code = null; - String message = null; - - if (response.code() == 301) { - code = "PermanentRedirect"; - message = "Moved Permanently"; - } else if (response.code() == 307) { - code = "Redirect"; - message = "Temporary redirect"; - } else if (response.code() == 400) { - code = "BadRequest"; - message = "Bad request"; - } - - String region = response.headers().get("x-amz-bucket-region"); - if (message != null && region != null) message += ". Use region " + region; - - if (retry - && region != null - && method.equals(Method.HEAD) - && bucketName != null - && regionCache.get(bucketName) != null) { - code = RETRY_HEAD; - message = null; - } - - return new String[] {code, message}; - } - - private String buildAwsUrl( - HttpUrl.Builder builder, String bucketName, boolean enforcePathStyle, String region) { - String host = this.awsS3Prefix + this.awsDomainSuffix; - if (host.equals("s3-external-1.amazonaws.com") - || host.equals("s3-us-gov-west-1.amazonaws.com") - || host.equals("s3-fips-us-gov-west-1.amazonaws.com")) { - builder.host(host); - return host; - } - - host = this.awsS3Prefix; - if (this.awsS3Prefix.contains("s3-accelerate")) { - if (bucketName.contains(".")) { - throw new IllegalArgumentException( - "bucket name '" + bucketName + "' with '.' is not allowed for accelerate endpoint"); - } - if (enforcePathStyle) host = host.replaceFirst("-accelerate", ""); - } - - if (this.awsDualstack) host += "dualstack."; - if (!this.awsS3Prefix.contains("s3-accelerate")) host += region + "."; - host += this.awsDomainSuffix; - - builder.host(host); - return host; - } - - private String buildListBucketsUrl(HttpUrl.Builder builder, String region) { - if (this.awsDomainSuffix == null) return null; - - String host = this.awsS3Prefix + this.awsDomainSuffix; - if (host.equals("s3-external-1.amazonaws.com") - || host.equals("s3-us-gov-west-1.amazonaws.com") - || host.equals("s3-fips-us-gov-west-1.amazonaws.com")) { - builder.host(host); - return host; - } - - String s3Prefix = this.awsS3Prefix; - String domainSuffix = this.awsDomainSuffix; - if (this.awsS3Prefix.startsWith("s3.") || this.awsS3Prefix.startsWith("s3-")) { - s3Prefix = "s3."; - domainSuffix = "amazonaws.com" + (domainSuffix.endsWith(".cn") ? ".cn" : ""); - } - - host = s3Prefix + region + "." + domainSuffix; - builder.host(host); - return host; - } - - /** Build URL for given parameters. */ - protected HttpUrl buildUrl( - Method method, - String bucketName, - String objectName, - String region, - Multimap queryParamMap) - throws NoSuchAlgorithmException { - if (bucketName == null && objectName != null) { - throw new IllegalArgumentException("null bucket name for object '" + objectName + "'"); - } - - HttpUrl.Builder urlBuilder = this.baseUrl.newBuilder(); - - if (queryParamMap != null) { - for (Map.Entry entry : queryParamMap.entries()) { - urlBuilder.addEncodedQueryParameter( - S3Escaper.encode(entry.getKey()), S3Escaper.encode(entry.getValue())); - } - } - - if (bucketName == null) { - this.buildListBucketsUrl(urlBuilder, region); - return urlBuilder.build(); - } - - boolean enforcePathStyle = ( - // use path style for make bucket to workaround "AuthorizationHeaderMalformed" error from - // s3.amazonaws.com - (method == Method.PUT && objectName == null && queryParamMap == null) - - // use path style for location query - || (queryParamMap != null && queryParamMap.containsKey("location")) - - // use path style where '.' in bucketName causes SSL certificate validation error - || (bucketName.contains(".") && this.baseUrl.isHttps())); - - String host = this.baseUrl.host(); - if (this.awsDomainSuffix != null) { - host = this.buildAwsUrl(urlBuilder, bucketName, enforcePathStyle, region); - } - - if (enforcePathStyle || !this.useVirtualStyle) { - urlBuilder.addEncodedPathSegment(S3Escaper.encode(bucketName)); - } else { - urlBuilder.host(bucketName + "." + host); - } - - if (objectName != null) { - urlBuilder.addEncodedPathSegments(S3Escaper.encodePath(objectName)); - } - - return urlBuilder.build(); - } - - /** Convert Multimap to Headers. */ - protected Headers httpHeaders(Multimap headerMap) { - Headers.Builder builder = new Headers.Builder(); - if (headerMap == null) return builder.build(); - - if (headerMap.containsKey("Content-Encoding")) { - builder.add( - "Content-Encoding", - headerMap.get("Content-Encoding").stream() - .distinct() - .filter(encoding -> !encoding.isEmpty()) - .collect(Collectors.joining(","))); - } - - for (Map.Entry entry : headerMap.entries()) { - if (!entry.getKey().equals("Content-Encoding")) { - builder.addUnsafeNonAscii(entry.getKey(), entry.getValue()); - } - } - - return builder.build(); - } - - /** Create HTTP request for given paramaters. */ - protected Request createRequest( - HttpUrl url, Method method, Headers headers, Object body, int length, Credentials creds) - throws InsufficientDataException, InternalException, IOException, NoSuchAlgorithmException { - Request.Builder requestBuilder = new Request.Builder(); - requestBuilder.url(url); - - if (headers != null) requestBuilder.headers(headers); - requestBuilder.header("Host", HttpUtils.getHostHeader(url)); - // Disable default gzip compression by okhttp library. - requestBuilder.header("Accept-Encoding", "identity"); - requestBuilder.header("User-Agent", this.userAgent); - - if (body != null && body instanceof RequestBody) { - return requestBuilder.method(method.toString(), (RequestBody) body).build(); - } - - String md5Hash = Digest.ZERO_MD5_HASH; - if (body != null) { - md5Hash = (body instanceof byte[]) ? Digest.md5Hash((byte[]) body, length) : null; - } - - String sha256Hash = null; - if (creds != null) { - sha256Hash = Digest.ZERO_SHA256_HASH; - if (!url.isHttps()) { - if (body != null) { - if (body instanceof PartSource) { - sha256Hash = ((PartSource) body).sha256Hash(); - } else if (body instanceof byte[]) { - sha256Hash = Digest.sha256Hash((byte[]) body, length); - } - } - } else { - // Fix issue #415: No need to compute sha256 if endpoint scheme is HTTPS. - sha256Hash = "UNSIGNED-PAYLOAD"; - if (body != null && body instanceof PartSource) { - sha256Hash = ((PartSource) body).sha256Hash(); - } - } - } - - if (md5Hash != null) requestBuilder.header("Content-MD5", md5Hash); - if (sha256Hash != null) requestBuilder.header("x-amz-content-sha256", sha256Hash); - - if (creds != null && creds.sessionToken() != null) { - requestBuilder.header("X-Amz-Security-Token", creds.sessionToken()); - } - - ZonedDateTime date = ZonedDateTime.now(); - requestBuilder.header("x-amz-date", date.format(Time.AMZ_DATE_FORMAT)); - - RequestBody requestBody = null; - if (body != null) { - String contentType = (headers != null) ? headers.get("Content-Type") : null; - if (contentType != null && MediaType.parse(contentType) == null) { - throw new IllegalArgumentException( - "invalid content type '" + contentType + "' as per RFC 2045"); - } - - if (body instanceof PartSource) { - requestBody = new HttpRequestBody((PartSource) body, contentType); - } else { - requestBody = new HttpRequestBody((byte[]) body, length, contentType); - } - } - - requestBuilder.method(method.toString(), requestBody); - return requestBuilder.build(); - } - - private StringBuilder newTraceBuilder(Request request, String body) { - StringBuilder traceBuilder = new StringBuilder(); - traceBuilder.append("---------START-HTTP---------\n"); - String encodedPath = request.url().encodedPath(); - String encodedQuery = request.url().encodedQuery(); - if (encodedQuery != null) encodedPath += "?" + encodedQuery; - traceBuilder.append(request.method()).append(" ").append(encodedPath).append(" HTTP/1.1\n"); - traceBuilder.append( - request - .headers() - .toString() - .replaceAll("Signature=([0-9a-f]+)", "Signature=*REDACTED*") - .replaceAll("Credential=([^/]+)", "Credential=*REDACTED*")); - if (body != null) traceBuilder.append("\n").append(body); - return traceBuilder; - } - - /** Execute HTTP request asynchronously for given parameters. */ - protected CompletableFuture executeAsync( - Method method, - String bucketName, - String objectName, - String region, - Headers headers, - Multimap queryParamMap, - Object body, - int length) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - boolean traceRequestBody = false; - if (body != null - && !(body instanceof PartSource || body instanceof byte[] || body instanceof RequestBody)) { - byte[] bytes; - if (body instanceof CharSequence) { - bytes = body.toString().getBytes(StandardCharsets.UTF_8); - } else { - bytes = Xml.marshal(body).getBytes(StandardCharsets.UTF_8); - } - - body = bytes; - length = bytes.length; - traceRequestBody = true; - } - - if (body == null && (method == Method.PUT || method == Method.POST)) { - body = HttpUtils.EMPTY_BODY; - } - - HttpUrl url = buildUrl(method, bucketName, objectName, region, queryParamMap); - Credentials creds = (provider == null) ? null : provider.fetch(); - Request req = createRequest(url, method, headers, body, length, creds); - if (!(body != null && body instanceof RequestBody) && creds != null) { - req = - Signer.signV4S3( - req, - region, - creds.accessKey(), - creds.secretKey(), - req.header("x-amz-content-sha256")); - } - final Request request = req; - - StringBuilder traceBuilder = - newTraceBuilder( - request, traceRequestBody ? new String((byte[]) body, StandardCharsets.UTF_8) : null); - PrintWriter traceStream = this.traceStream; - if (traceStream != null) traceStream.println(traceBuilder.toString()); - traceBuilder.append("\n"); - - OkHttpClient httpClient = this.httpClient; - if (!(body instanceof byte[]) && (method == Method.PUT || method == Method.POST)) { - // Issue #924: disable connection retry for PUT and POST methods for other than byte array. - httpClient = this.httpClient.newBuilder().retryOnConnectionFailure(false).build(); - } - - CompletableFuture completableFuture = new CompletableFuture<>(); - httpClient - .newCall(request) - .enqueue( - new Callback() { - @Override - public void onFailure(final Call call, IOException e) { - completableFuture.completeExceptionally(e); - } - - @Override - public void onResponse(Call call, final Response response) throws IOException { - try { - onResponse(response); - } catch (Exception e) { - completableFuture.completeExceptionally(e); - } - } - - private void onResponse(final Response response) throws IOException { - String trace = - response.protocol().toString().toUpperCase(Locale.US) - + " " - + response.code() - + "\n" - + response.headers(); - traceBuilder.append(trace).append("\n"); - if (traceStream != null) traceStream.println(trace); - - if (response.isSuccessful()) { - if (traceStream != null) { - // Trace response body only if the request is not - // GetObject/ListenBucketNotification - // S3 API. - Set keys = queryParamMap.keySet(); - if ((method != Method.GET - || objectName == null - || !Collections.disjoint(keys, TRACE_QUERY_PARAMS)) - && !(keys.contains("events") - && (keys.contains("prefix") || keys.contains("suffix")))) { - ResponseBody responseBody = response.peekBody(1024 * 1024); - traceStream.println(responseBody.string()); - } - traceStream.println(END_HTTP); - } - - completableFuture.complete(response); - return; - } - - String errorXml = null; - try (ResponseBody responseBody = response.body()) { - errorXml = responseBody.string(); - } - - if (!("".equals(errorXml) && method.equals(Method.HEAD))) { - traceBuilder.append(errorXml).append("\n"); - if (traceStream != null) traceStream.println(errorXml); - } - - traceBuilder.append(END_HTTP).append("\n"); - if (traceStream != null) traceStream.println(END_HTTP); - - // Error in case of Non-XML response from server for non-HEAD requests. - String contentType = response.headers().get("content-type"); - if (!method.equals(Method.HEAD) - && (contentType == null - || !Arrays.asList(contentType.split(";")).contains("application/xml"))) { - if (response.code() == 304 && response.body().contentLength() == 0) { - completableFuture.completeExceptionally( - new ServerException( - "server failed with HTTP status code " + response.code(), - response.code(), - traceBuilder.toString())); - } - - completableFuture.completeExceptionally( - new InvalidResponseException( - response.code(), - contentType, - errorXml.substring( - 0, errorXml.length() > 1024 ? 1024 : errorXml.length()), - traceBuilder.toString())); - return; - } - - ErrorResponse errorResponse = null; - if (!"".equals(errorXml)) { - try { - errorResponse = Xml.unmarshal(ErrorResponse.class, errorXml); - } catch (XmlParserException e) { - completableFuture.completeExceptionally(e); - return; - } - } else if (!method.equals(Method.HEAD)) { - completableFuture.completeExceptionally( - new InvalidResponseException( - response.code(), contentType, errorXml, traceBuilder.toString())); - return; - } - - if (errorResponse == null) { - String code = null; - String message = null; - switch (response.code()) { - case 301: - case 307: - case 400: - String[] result = handleRedirectResponse(method, bucketName, response, true); - code = result[0]; - message = result[1]; - break; - case 404: - if (objectName != null) { - code = "NoSuchKey"; - message = "Object does not exist"; - } else if (bucketName != null) { - code = NO_SUCH_BUCKET; - message = NO_SUCH_BUCKET_MESSAGE; - } else { - code = "ResourceNotFound"; - message = "Request resource not found"; - } - break; - case 501: - case 405: - code = "MethodNotAllowed"; - message = "The specified method is not allowed against this resource"; - break; - case 409: - if (bucketName != null) { - code = NO_SUCH_BUCKET; - message = NO_SUCH_BUCKET_MESSAGE; - } else { - code = "ResourceConflict"; - message = "Request resource conflicts"; - } - break; - case 403: - code = "AccessDenied"; - message = "Access denied"; - break; - case 412: - code = "PreconditionFailed"; - message = "At least one of the preconditions you specified did not hold"; - break; - case 416: - code = "InvalidRange"; - message = "The requested range cannot be satisfied"; - break; - default: - completableFuture.completeExceptionally( - new ServerException( - "server failed with HTTP status code " + response.code(), - response.code(), - traceBuilder.toString())); - return; - } - - errorResponse = - new ErrorResponse( - code, - message, - bucketName, - objectName, - request.url().encodedPath(), - response.header("x-amz-request-id"), - response.header("x-amz-id-2")); - } - - // invalidate region cache if needed - if (errorResponse.code().equals(NO_SUCH_BUCKET) - || errorResponse.code().equals(RETRY_HEAD)) { - regionCache.remove(bucketName); - } - - ErrorResponseException e = - new ErrorResponseException(errorResponse, response, traceBuilder.toString()); - completableFuture.completeExceptionally(e); - } - }); - return completableFuture; - } - - /** Execute HTTP request asynchronously for given args and parameters. */ - protected CompletableFuture executeAsync( - Method method, - BaseArgs args, - Multimap headers, - Multimap queryParams, - Object body, - int length) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - final Multimap extraHeaders; - final Multimap extraQueryParams; - final String bucketName; - final String region; - final String objectName; - - if (args != null) { - extraHeaders = args.extraHeaders(); - extraQueryParams = args.extraQueryParams(); - - if (args instanceof BucketArgs) { - bucketName = ((BucketArgs) args).bucket(); - region = ((BucketArgs) args).region(); - } else { - bucketName = null; - region = null; - } - - if (args instanceof ObjectArgs) { - objectName = ((ObjectArgs) args).object(); - } else { - objectName = null; - } - } else { - extraHeaders = null; - extraQueryParams = null; - bucketName = null; - region = null; - objectName = null; - } - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - method, - bucketName, - objectName, - location, - httpHeaders(merge(extraHeaders, headers)), - merge(extraQueryParams, queryParams), - body, - length); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }); - } - - /** - * Execute HTTP request for given parameters. - * - * @deprecated This method is no longer supported. Use {@link #executeAsync}. - */ - @Deprecated - protected Response execute( - Method method, - String bucketName, - String objectName, - String region, - Headers headers, - Multimap queryParamMap, - Object body, - int length) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - CompletableFuture completableFuture = - executeAsync(method, bucketName, objectName, region, headers, queryParamMap, body, length); - try { - return completableFuture.get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Execute HTTP request for given args and parameters. - * - * @deprecated This method is no longer supported. Use {@link #executeAsync}. - */ - @Deprecated - protected Response execute( - Method method, - BaseArgs args, - Multimap headers, - Multimap queryParams, - Object body, - int length) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - String bucketName = null; - String region = null; - String objectName = null; - - if (args instanceof BucketArgs) { - bucketName = ((BucketArgs) args).bucket(); - region = ((BucketArgs) args).region(); - } - - if (args instanceof ObjectArgs) objectName = ((ObjectArgs) args).object(); - - return execute( - method, - bucketName, - objectName, - getRegion(bucketName, region), - httpHeaders(merge(args.extraHeaders(), headers)), - merge(args.extraQueryParams(), queryParams), - body, - length); - } - - /** Returns region of given bucket either from region cache or set in constructor. */ - protected CompletableFuture getRegionAsync(String bucketName, String region) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - if (region != null) { - // Error out if region does not match with region passed via constructor. - if (this.region != null && !this.region.equals(region)) { - throw new IllegalArgumentException( - "region must be " + this.region + ", but passed " + region); - } - return CompletableFuture.completedFuture(region); - } - - if (this.region != null && !this.region.equals("")) { - return CompletableFuture.completedFuture(this.region); - } - if (bucketName == null || this.provider == null) { - return CompletableFuture.completedFuture(US_EAST_1); - } - region = regionCache.get(bucketName); - if (region != null) return CompletableFuture.completedFuture(region); - - // Execute GetBucketLocation REST API to get region of the bucket. - CompletableFuture future = - executeAsync( - Method.GET, bucketName, null, US_EAST_1, null, newMultimap("location", null), null, 0); - return future.thenApply( - response -> { - String location; - try (ResponseBody body = response.body()) { - LocationConstraint lc = Xml.unmarshal(LocationConstraint.class, body.charStream()); - if (lc.location() == null || lc.location().equals("")) { - location = US_EAST_1; - } else if (lc.location().equals("EU") && this.awsDomainSuffix != null) { - location = "eu-west-1"; // eu-west-1 is also referred as 'EU'. - } else { - location = lc.location(); - } - } catch (XmlParserException e) { - throw new CompletionException(e); - } - - regionCache.put(bucketName, location); - return location; - }); - } - - /** - * Returns region of given bucket either from region cache or set in constructor. - * - * @deprecated This method is no longer supported. Use {@link #getRegionAsync}. - */ - @Deprecated - protected String getRegion(String bucketName, String region) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return getRegionAsync(bucketName, region).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** Execute asynchronously GET HTTP request for given parameters. */ - protected CompletableFuture executeGetAsync( - BaseArgs args, Multimap headers, Multimap queryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return executeAsync(Method.GET, args, headers, queryParams, null, 0); - } - - /** - * Execute GET HTTP request for given parameters. - * - * @deprecated This method is no longer supported. Use {@link #executeGetAsync}. - */ - @Deprecated - protected Response executeGet( - BaseArgs args, Multimap headers, Multimap queryParams) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return executeGetAsync(args, headers, queryParams).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** Execute asynchronously HEAD HTTP request for given parameters. */ - protected CompletableFuture executeHeadAsync( - BaseArgs args, Multimap headers, Multimap queryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return executeAsync(Method.HEAD, args, headers, queryParams, null, 0) - .exceptionally( - e -> { - if (e instanceof ErrorResponseException) { - ErrorResponseException ex = (ErrorResponseException) e; - if (ex.errorResponse().code().equals(RETRY_HEAD)) { - return null; - } - } - throw new CompletionException(e); - }) - .thenCompose( - response -> { - if (response != null) { - return CompletableFuture.completedFuture(response); - } - - try { - return executeAsync(Method.HEAD, args, headers, queryParams, null, 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }); - } - - /** - * Execute HEAD HTTP request for given parameters. - * - * @deprecated This method is no longer supported. Use {@link #executeHeadAsync}. - */ - @Deprecated - protected Response executeHead( - BaseArgs args, Multimap headers, Multimap queryParams) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return executeHeadAsync(args, headers, queryParams).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** Execute asynchronously DELETE HTTP request for given parameters. */ - protected CompletableFuture executeDeleteAsync( - BaseArgs args, Multimap headers, Multimap queryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return executeAsync(Method.DELETE, args, headers, queryParams, null, 0) - .thenApply( - response -> { - if (response != null) response.body().close(); - return response; - }); - } - - /** - * Execute DELETE HTTP request for given parameters. - * - * @deprecated This method is no longer supported. Use {@link #executeDeleteAsync}. - */ - @Deprecated - protected Response executeDelete( - BaseArgs args, Multimap headers, Multimap queryParams) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return executeDeleteAsync(args, headers, queryParams).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** Execute asynchronously POST HTTP request for given parameters. */ - protected CompletableFuture executePostAsync( - BaseArgs args, - Multimap headers, - Multimap queryParams, - Object data) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return executeAsync(Method.POST, args, headers, queryParams, data, 0); - } - - /** - * Execute POST HTTP request for given parameters. - * - * @deprecated This method is no longer supported. Use {@link #executePostAsync}. - */ - @Deprecated - protected Response executePost( - BaseArgs args, - Multimap headers, - Multimap queryParams, - Object data) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return executePostAsync(args, headers, queryParams, data).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** Execute asynchronously PUT HTTP request for given parameters. */ - protected CompletableFuture executePutAsync( - BaseArgs args, - Multimap headers, - Multimap queryParams, - Object data, - int length) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return executeAsync(Method.PUT, args, headers, queryParams, data, length); - } - - /** - * Execute PUT HTTP request for given parameters. - * - * @deprecated This method is no longer supported. Use {@link #executePutAsync}. - */ - @Deprecated - protected Response executePut( - BaseArgs args, - Multimap headers, - Multimap queryParams, - Object data, - int length) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return executePutAsync(args, headers, queryParams, data, length).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - protected CompletableFuture calculatePartCountAsync(List sources) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - long[] objectSize = {0}; - int index = 0; - - CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> 0); - for (ComposeSource src : sources) { - index++; - final int i = index; - completableFuture = - completableFuture.thenCombine( - statObjectAsync(new StatObjectArgs((ObjectReadArgs) src)), - (partCount, statObjectResponse) -> { - src.buildHeaders(statObjectResponse.size(), statObjectResponse.etag()); - - long size = statObjectResponse.size(); - if (src.length() != null) { - size = src.length(); - } else if (src.offset() != null) { - size -= src.offset(); - } - - if (size < ObjectWriteArgs.MIN_MULTIPART_SIZE - && sources.size() != 1 - && i != sources.size()) { - throw new IllegalArgumentException( - "source " - + src.bucket() - + "/" - + src.object() - + ": size " - + size - + " must be greater than " - + ObjectWriteArgs.MIN_MULTIPART_SIZE); - } - - objectSize[0] += size; - if (objectSize[0] > ObjectWriteArgs.MAX_OBJECT_SIZE) { - throw new IllegalArgumentException( - "destination object size must be less than " - + ObjectWriteArgs.MAX_OBJECT_SIZE); - } - - if (size > ObjectWriteArgs.MAX_PART_SIZE) { - long count = size / ObjectWriteArgs.MAX_PART_SIZE; - long lastPartSize = size - (count * ObjectWriteArgs.MAX_PART_SIZE); - if (lastPartSize > 0) { - count++; - } else { - lastPartSize = ObjectWriteArgs.MAX_PART_SIZE; - } - - if (lastPartSize < ObjectWriteArgs.MIN_MULTIPART_SIZE - && sources.size() != 1 - && i != sources.size()) { - throw new IllegalArgumentException( - "source " - + src.bucket() - + "/" - + src.object() - + ": " - + "for multipart split upload of " - + size - + ", last part size is less than " - + ObjectWriteArgs.MIN_MULTIPART_SIZE); - } - partCount += (int) count; - } else { - partCount++; - } - - if (partCount > ObjectWriteArgs.MAX_MULTIPART_COUNT) { - throw new IllegalArgumentException( - "Compose sources create more than allowed multipart count " - + ObjectWriteArgs.MAX_MULTIPART_COUNT); - } - return partCount; - }); - } - - return completableFuture; - } - - /** Calculate part count of given compose sources. */ - @Deprecated - protected int calculatePartCount(List sources) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - long objectSize = 0; - int partCount = 0; - int i = 0; - for (ComposeSource src : sources) { - i++; - StatObjectResponse stat = null; - try { - stat = statObjectAsync(new StatObjectArgs((ObjectReadArgs) src)).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - } - - src.buildHeaders(stat.size(), stat.etag()); - - long size = stat.size(); - if (src.length() != null) { - size = src.length(); - } else if (src.offset() != null) { - size -= src.offset(); - } - - if (size < ObjectWriteArgs.MIN_MULTIPART_SIZE && sources.size() != 1 && i != sources.size()) { - throw new IllegalArgumentException( - "source " - + src.bucket() - + "/" - + src.object() - + ": size " - + size - + " must be greater than " - + ObjectWriteArgs.MIN_MULTIPART_SIZE); - } - - objectSize += size; - if (objectSize > ObjectWriteArgs.MAX_OBJECT_SIZE) { - throw new IllegalArgumentException( - "destination object size must be less than " + ObjectWriteArgs.MAX_OBJECT_SIZE); - } - - if (size > ObjectWriteArgs.MAX_PART_SIZE) { - long count = size / ObjectWriteArgs.MAX_PART_SIZE; - long lastPartSize = size - (count * ObjectWriteArgs.MAX_PART_SIZE); - if (lastPartSize > 0) { - count++; - } else { - lastPartSize = ObjectWriteArgs.MAX_PART_SIZE; - } - - if (lastPartSize < ObjectWriteArgs.MIN_MULTIPART_SIZE - && sources.size() != 1 - && i != sources.size()) { - throw new IllegalArgumentException( - "source " - + src.bucket() - + "/" - + src.object() - + ": " - + "for multipart split upload of " - + size - + ", last part size is less than " - + ObjectWriteArgs.MIN_MULTIPART_SIZE); - } - partCount += (int) count; - } else { - partCount++; - } - - if (partCount > ObjectWriteArgs.MAX_MULTIPART_COUNT) { - throw new IllegalArgumentException( - "Compose sources create more than allowed multipart count " - + ObjectWriteArgs.MAX_MULTIPART_COUNT); - } - } - - return partCount; - } - - private abstract class ObjectIterator implements Iterator> { - protected Result error; - protected Iterator itemIterator; - protected Iterator deleteMarkerIterator; - protected Iterator prefixIterator; - protected boolean completed = false; - protected ListObjectsResult listObjectsResult; - protected String lastObjectName; - - protected abstract void populateResult() - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException; - - protected synchronized void populate() { - try { - populateResult(); - } catch (ErrorResponseException - | InsufficientDataException - | InternalException - | InvalidKeyException - | InvalidResponseException - | IOException - | NoSuchAlgorithmException - | ServerException - | XmlParserException e) { - this.error = new Result<>(e); - } - - if (this.listObjectsResult != null) { - this.itemIterator = this.listObjectsResult.contents().iterator(); - this.deleteMarkerIterator = this.listObjectsResult.deleteMarkers().iterator(); - this.prefixIterator = this.listObjectsResult.commonPrefixes().iterator(); - } else { - this.itemIterator = new LinkedList().iterator(); - this.deleteMarkerIterator = new LinkedList().iterator(); - this.prefixIterator = new LinkedList().iterator(); - } - } - - @Override - public boolean hasNext() { - if (this.completed) return false; - - if (this.error == null - && this.itemIterator == null - && this.deleteMarkerIterator == null - && this.prefixIterator == null) { - populate(); - } - - if (this.error == null - && !this.itemIterator.hasNext() - && !this.deleteMarkerIterator.hasNext() - && !this.prefixIterator.hasNext() - && this.listObjectsResult.isTruncated()) { - populate(); - } - - if (this.error != null) return true; - if (this.itemIterator.hasNext()) return true; - if (this.deleteMarkerIterator.hasNext()) return true; - if (this.prefixIterator.hasNext()) return true; - - this.completed = true; - return false; - } - - @Override - public Result next() { - if (this.completed) throw new NoSuchElementException(); - if (this.error == null - && this.itemIterator == null - && this.deleteMarkerIterator == null - && this.prefixIterator == null) { - populate(); - } - - if (this.error == null - && !this.itemIterator.hasNext() - && !this.deleteMarkerIterator.hasNext() - && !this.prefixIterator.hasNext() - && this.listObjectsResult.isTruncated()) { - populate(); - } - - if (this.error != null) { - this.completed = true; - return this.error; - } - - Item item = null; - if (this.itemIterator.hasNext()) { - item = this.itemIterator.next(); - item.setEncodingType(this.listObjectsResult.encodingType()); - this.lastObjectName = item.objectName(); - } else if (this.deleteMarkerIterator.hasNext()) { - item = this.deleteMarkerIterator.next(); - } else if (this.prefixIterator.hasNext()) { - item = this.prefixIterator.next().toItem(); - } - - if (item != null) { - item.setEncodingType(this.listObjectsResult.encodingType()); - return new Result<>(item); - } - - this.completed = true; - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /** Execute list objects v2. */ - protected Iterable> listObjectsV2(ListObjectsArgs args) { - return new Iterable>() { - @Override - public Iterator> iterator() { - return new ObjectIterator() { - private ListBucketResultV2 result = null; - - @Override - protected void populateResult() - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, - NoSuchAlgorithmException, ServerException, XmlParserException { - this.listObjectsResult = null; - this.itemIterator = null; - this.prefixIterator = null; - - try { - ListObjectsV2Response response = - listObjectsV2Async( - args.bucket(), - args.region(), - args.delimiter(), - args.useUrlEncodingType() ? "url" : null, - args.startAfter(), - args.maxKeys(), - args.prefix(), - (result == null) - ? args.continuationToken() - : result.nextContinuationToken(), - args.fetchOwner(), - args.includeUserMetadata(), - args.extraHeaders(), - args.extraQueryParams()) - .get(); - result = response.result(); - this.listObjectsResult = response.result(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - } - } - }; - } - }; - } - - /** Execute list objects v1. */ - protected Iterable> listObjectsV1(ListObjectsArgs args) { - return new Iterable>() { - @Override - public Iterator> iterator() { - return new ObjectIterator() { - private ListBucketResultV1 result = null; - - @Override - protected void populateResult() - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, - NoSuchAlgorithmException, ServerException, XmlParserException { - this.listObjectsResult = null; - this.itemIterator = null; - this.prefixIterator = null; - - String nextMarker = (result == null) ? args.marker() : result.nextMarker(); - if (nextMarker == null) nextMarker = this.lastObjectName; - - try { - ListObjectsV1Response response = - listObjectsV1Async( - args.bucket(), - args.region(), - args.delimiter(), - args.useUrlEncodingType() ? "url" : null, - nextMarker, - args.maxKeys(), - args.prefix(), - args.extraHeaders(), - args.extraQueryParams()) - .get(); - result = response.result(); - this.listObjectsResult = response.result(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - } - } - }; - } - }; - } - - /** Execute list object versions. */ - protected Iterable> listObjectVersions(ListObjectsArgs args) { - return new Iterable>() { - @Override - public Iterator> iterator() { - return new ObjectIterator() { - private ListVersionsResult result = null; - - @Override - protected void populateResult() - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, - NoSuchAlgorithmException, ServerException, XmlParserException { - this.listObjectsResult = null; - this.itemIterator = null; - this.prefixIterator = null; - - try { - ListObjectVersionsResponse response = - listObjectVersionsAsync( - args.bucket(), - args.region(), - args.delimiter(), - args.useUrlEncodingType() ? "url" : null, - (result == null) ? args.keyMarker() : result.nextKeyMarker(), - args.maxKeys(), - args.prefix(), - (result == null) ? args.versionIdMarker() : result.nextVersionIdMarker(), - args.extraHeaders(), - args.extraQueryParams()) - .get(); - result = response.result(); - this.listObjectsResult = response.result(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - } - } - }; - } - }; - } - - protected PartReader newPartReader(Object data, long objectSize, long partSize, int partCount) { - if (data instanceof RandomAccessFile) { - return new PartReader((RandomAccessFile) data, objectSize, partSize, partCount); - } - - if (data instanceof InputStream) { - return new PartReader((InputStream) data, objectSize, partSize, partCount); - } - - return null; - } - - /** - * Execute put object. - * - * @deprecated This method is no longer supported. Use {@link #putObjectAsync}. - */ - @Deprecated - protected ObjectWriteResponse putObject( - PutObjectBaseArgs args, - Object data, - long objectSize, - long partSize, - int partCount, - String contentType) - throws ErrorResponseException, InsufficientDataException, InternalException, - InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, - ServerException, XmlParserException { - try { - return putObjectAsync(args, data, objectSize, partSize, partCount, contentType).get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** Notification result records representation. */ - protected static class NotificationResultRecords { - Response response = null; - Scanner scanner = null; - ObjectMapper mapper = null; - - public NotificationResultRecords(Response response) { - this.response = response; - this.scanner = new Scanner(response.body().charStream()).useDelimiter("\n"); - this.mapper = - JsonMapper.builder() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true) - .build(); - } - - /** returns closeable iterator of result of notification records. */ - public CloseableIterator> closeableIterator() { - return new CloseableIterator>() { - String recordsString = null; - NotificationRecords records = null; - boolean isClosed = false; - - @Override - public void close() throws IOException { - if (!isClosed) { - try { - response.body().close(); - scanner.close(); - } finally { - isClosed = true; - } - } - } - - public boolean populate() { - if (isClosed) return false; - if (recordsString != null) return true; - - while (scanner.hasNext()) { - recordsString = scanner.next().trim(); - if (!recordsString.equals("")) break; - } - - if (recordsString == null || recordsString.equals("")) { - try { - close(); - } catch (IOException e) { - isClosed = true; - } - return false; - } - return true; - } - - @Override - public boolean hasNext() { - return populate(); - } - - @Override - public Result next() { - if (isClosed) throw new NoSuchElementException(); - if ((recordsString == null || recordsString.equals("")) && !populate()) { - throw new NoSuchElementException(); - } - - try { - records = mapper.readValue(recordsString, NotificationRecords.class); - return new Result<>(records); - } catch (JsonMappingException e) { - return new Result<>(e); - } catch (JsonParseException e) { - return new Result<>(e); - } catch (IOException e) { - return new Result<>(e); - } finally { - recordsString = null; - records = null; - } - } - }; - } - } - - private Multimap getCommonListObjectsQueryParams( - String delimiter, String encodingType, Integer maxKeys, String prefix) { - Multimap queryParams = - newMultimap( - "delimiter", - (delimiter == null) ? "" : delimiter, - "max-keys", - Integer.toString(maxKeys > 0 ? maxKeys : 1000), - "prefix", - (prefix == null) ? "" : prefix); - if (encodingType != null) queryParams.put("encoding-type", encodingType); - return queryParams; - } - - /** - * Sets HTTP connect, write and read timeouts. A value of 0 means no timeout, otherwise values - * must be between 1 and Integer.MAX_VALUE when converted to milliseconds. - * - *

Example:{@code
-   * minioClient.setTimeout(TimeUnit.SECONDS.toMillis(10), TimeUnit.SECONDS.toMillis(10),
-   *     TimeUnit.SECONDS.toMillis(30));
-   * }
- * - * @param connectTimeout HTTP connect timeout in milliseconds. - * @param writeTimeout HTTP write timeout in milliseconds. - * @param readTimeout HTTP read timeout in milliseconds. - */ - public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) { - this.httpClient = - HttpUtils.setTimeout(this.httpClient, connectTimeout, writeTimeout, readTimeout); - } - - /** - * Ignores check on server certificate for HTTPS connection. - * - *
Example:{@code
-   * minioClient.ignoreCertCheck();
-   * }
- * - * @throws KeyManagementException thrown to indicate key management error. - * @throws NoSuchAlgorithmException thrown to indicate missing of SSL library. - */ - @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.") - public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmException { - this.httpClient = HttpUtils.disableCertCheck(this.httpClient); - } - - /** - * Sets application's name/version to user agent. For more information about user agent refer #rfc2616. - * - * @param name Your application name. - * @param version Your application version. - */ - public void setAppInfo(String name, String version) { - if (name == null || version == null) return; - this.userAgent = - MinioProperties.INSTANCE.getDefaultUserAgent() + " " + name.trim() + "/" + version.trim(); - } - - /** - * Enables HTTP call tracing and written to traceStream. - * - * @param traceStream {@link OutputStream} for writing HTTP call tracing. - * @see #traceOff - */ - public void traceOn(OutputStream traceStream) { - if (traceStream == null) throw new IllegalArgumentException("trace stream must be provided"); - this.traceStream = - new PrintWriter(new OutputStreamWriter(traceStream, StandardCharsets.UTF_8), true); - } - - /** - * Disables HTTP call tracing previously enabled. - * - * @see #traceOn - * @throws IOException upon connection error - */ - public void traceOff() throws IOException { - this.traceStream = null; - } - - /** - * Enables accelerate endpoint for Amazon S3 endpoint. - * - * @deprecated This method is no longer supported. - */ - @Deprecated - public void enableAccelerateEndpoint() { - this.awsS3Prefix = "s3-accelerate."; - } - - /** - * Disables accelerate endpoint for Amazon S3 endpoint. - * - * @deprecated This method is no longer supported. - */ - @Deprecated - public void disableAccelerateEndpoint() { - this.awsS3Prefix = "s3."; - } - - /** Enables dual-stack endpoint for Amazon S3 endpoint. */ - public void enableDualStackEndpoint() { - this.awsDualstack = true; - } - - /** Disables dual-stack endpoint for Amazon S3 endpoint. */ - public void disableDualStackEndpoint() { - this.awsDualstack = false; - } - - /** Enables virtual-style endpoint. */ - public void enableVirtualStyleEndpoint() { - this.useVirtualStyle = true; - } - - /** Disables virtual-style endpoint. */ - public void disableVirtualStyleEndpoint() { - this.useVirtualStyle = false; - } - - /** Sets AWS S3 domain prefix. */ - public void setAwsS3Prefix(@Nonnull String awsS3Prefix) { - if (awsS3Prefix == null) throw new IllegalArgumentException("null Amazon AWS S3 domain prefix"); - if (!HttpUtils.AWS_S3_PREFIX_REGEX.matcher(awsS3Prefix).find()) { - throw new IllegalArgumentException("invalid Amazon AWS S3 domain prefix " + awsS3Prefix); - } - this.awsS3Prefix = awsS3Prefix; - } - - /** Execute stat object a.k.a head object S3 API asynchronously. */ - protected CompletableFuture statObjectAsync(StatObjectArgs args) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - checkArgs(args); - args.validateSsec(baseUrl); - return executeHeadAsync( - args, - args.getHeaders(), - (args.versionId() != null) ? newMultimap("versionId", args.versionId()) : null) - .thenApply( - response -> - new StatObjectResponse( - response.headers(), args.bucket(), args.region(), args.object())); - } - - /** - * Do AbortMultipartUpload - * S3 API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket. - * @param objectName Object name in the bucket. - * @param uploadId Upload ID. - * @param extraHeaders Extra headers (Optional). - * @param extraQueryParams Extra query parameters (Optional). - * @return {@link CompletableFuture}<{@link AbortMultipartUploadResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture abortMultipartUploadAsync( - String bucketName, - String region, - String objectName, - String uploadId, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.DELETE, - bucketName, - objectName, - location, - httpHeaders(extraHeaders), - merge(extraQueryParams, newMultimap(UPLOAD_ID, uploadId)), - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - return new AbortMultipartUploadResponse( - response.headers(), bucketName, region, objectName, uploadId); - } finally { - response.close(); - } - }); - } - - /** - * Do AbortMultipartUpload - * S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket. - * @param objectName Object name in the bucket. - * @param uploadId Upload ID. - * @param extraHeaders Extra headers (Optional). - * @param extraQueryParams Extra query parameters (Optional). - * @return {@link AbortMultipartUploadResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #abortMultipartUploadAsync}. - */ - @Deprecated - protected AbortMultipartUploadResponse abortMultipartUpload( - String bucketName, - String region, - String objectName, - String uploadId, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return abortMultipartUploadAsync( - bucketName, region, objectName, uploadId, extraHeaders, extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do CompleteMultipartUpload - * S3 API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket. - * @param objectName Object name in the bucket. - * @param uploadId Upload ID. - * @param parts List of parts. - * @param extraHeaders Extra headers (Optional). - * @param extraQueryParams Extra query parameters (Optional). - * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture completeMultipartUploadAsync( - String bucketName, - String region, - String objectName, - String uploadId, - Part[] parts, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = newMultimap(extraQueryParams); - queryParams.put(UPLOAD_ID, uploadId); - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.POST, - bucketName, - objectName, - location, - httpHeaders(extraHeaders), - queryParams, - new CompleteMultipartUpload(parts), - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - String bodyContent = response.body().string(); - bodyContent = bodyContent.trim(); - if (!bodyContent.isEmpty()) { - try { - if (Xml.validate(ErrorResponse.class, bodyContent)) { - ErrorResponse errorResponse = Xml.unmarshal(ErrorResponse.class, bodyContent); - throw new CompletionException( - new ErrorResponseException(errorResponse, response, null)); - } - } catch (XmlParserException e) { - // As it is not message, fallback to parse CompleteMultipartUploadOutput - // XML. - } - - try { - CompleteMultipartUploadResult result = - Xml.unmarshal(CompleteMultipartUploadResult.class, bodyContent); - return new ObjectWriteResponse( - response.headers(), - result.bucket(), - result.location(), - result.object(), - result.etag(), - response.header("x-amz-version-id"), - result); - } catch (XmlParserException e) { - // As this CompleteMultipartUpload REST call succeeded, just log it. - Logger.getLogger(S3Base.class.getName()) - .warning( - "S3 service returned unknown XML for CompleteMultipartUpload REST API. " - + bodyContent); - } - } - - return new ObjectWriteResponse( - response.headers(), - bucketName, - region, - objectName, - null, - response.header("x-amz-version-id")); - } catch (IOException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do CompleteMultipartUpload - * S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket. - * @param objectName Object name in the bucket. - * @param uploadId Upload ID. - * @param parts List of parts. - * @param extraHeaders Extra headers (Optional). - * @param extraQueryParams Extra query parameters (Optional). - * @return {@link ObjectWriteResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #completeMultipartUploadAsync}. - */ - @Deprecated - protected ObjectWriteResponse completeMultipartUpload( - String bucketName, - String region, - String objectName, - String uploadId, - Part[] parts, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return completeMultipartUploadAsync( - bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do CreateMultipartUpload - * S3 API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region name of buckets in S3 service. - * @param objectName Object name in the bucket. - * @param headers Request headers. - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link CreateMultipartUploadResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture createMultipartUploadAsync( - String bucketName, - String region, - String objectName, - Multimap headers, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = newMultimap(extraQueryParams); - queryParams.put("uploads", ""); - - Multimap headersCopy = newMultimap(headers); - // set content type if not set already - if (!headersCopy.containsKey("Content-Type")) { - headersCopy.put("Content-Type", "application/octet-stream"); - } - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.POST, - bucketName, - objectName, - location, - httpHeaders(headersCopy), - queryParams, - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - InitiateMultipartUploadResult result = - Xml.unmarshal( - InitiateMultipartUploadResult.class, response.body().charStream()); - return new CreateMultipartUploadResponse( - response.headers(), bucketName, region, objectName, result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do CreateMultipartUpload - * S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region name of buckets in S3 service. - * @param objectName Object name in the bucket. - * @param headers Request headers. - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CreateMultipartUploadResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #createMultipartUploadAsync}. - */ - @Deprecated - protected CreateMultipartUploadResponse createMultipartUpload( - String bucketName, - String region, - String objectName, - Multimap headers, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return createMultipartUploadAsync(bucketName, region, objectName, headers, extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do DeleteObjects S3 - * API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectList List of object names. - * @param quiet Quiet flag. - * @param bypassGovernanceMode Bypass Governance retention mode. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link DeleteObjectsResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture deleteObjectsAsync( - String bucketName, - String region, - List objectList, - boolean quiet, - boolean bypassGovernanceMode, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - if (objectList == null) objectList = new LinkedList<>(); - - if (objectList.size() > 1000) { - throw new IllegalArgumentException("list of objects must not be more than 1000"); - } - - Multimap headers = - merge( - extraHeaders, - bypassGovernanceMode ? newMultimap("x-amz-bypass-governance-retention", "true") : null); - - final List objects = objectList; - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.POST, - bucketName, - null, - location, - httpHeaders(headers), - merge(extraQueryParams, newMultimap("delete", "")), - new DeleteRequest(objects, quiet), - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - String bodyContent = response.body().string(); - try { - if (Xml.validate(DeleteError.class, bodyContent)) { - DeleteError error = Xml.unmarshal(DeleteError.class, bodyContent); - DeleteResult result = new DeleteResult(error); - return new DeleteObjectsResponse( - response.headers(), bucketName, region, result); - } - } catch (XmlParserException e) { - // Ignore this exception as it is not message, - // but parse it as message below. - } - - DeleteResult result = Xml.unmarshal(DeleteResult.class, bodyContent); - return new DeleteObjectsResponse(response.headers(), bucketName, region, result); - } catch (IOException | XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do DeleteObjects S3 - * API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectList List of object names. - * @param quiet Quiet flag. - * @param bypassGovernanceMode Bypass Governance retention mode. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link DeleteObjectsResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #deleteObjectsAsync}. - */ - @Deprecated - protected DeleteObjectsResponse deleteObjects( - String bucketName, - String region, - List objectList, - boolean quiet, - boolean bypassGovernanceMode, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return deleteObjectsAsync( - bucketName, - region, - objectList, - quiet, - bypassGovernanceMode, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do ListObjects - * version 2 S3 API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param startAfter Fetch listing after this key (Optional). - * @param maxKeys Maximum object information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param continuationToken Continuation token (Optional). - * @param fetchOwner Flag to fetch owner information (Optional). - * @param includeUserMetadata MinIO extension flag to include user metadata (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link ListObjectsV2Response}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture listObjectsV2Async( - String bucketName, - String region, - String delimiter, - String encodingType, - String startAfter, - Integer maxKeys, - String prefix, - String continuationToken, - boolean fetchOwner, - boolean includeUserMetadata, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = - merge( - extraQueryParams, - getCommonListObjectsQueryParams(delimiter, encodingType, maxKeys, prefix)); - queryParams.put("list-type", "2"); - if (continuationToken != null) queryParams.put("continuation-token", continuationToken); - if (fetchOwner) queryParams.put("fetch-owner", "true"); - if (startAfter != null) queryParams.put("start-after", startAfter); - if (includeUserMetadata) queryParams.put("metadata", "true"); - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.GET, - bucketName, - null, - location, - httpHeaders(extraHeaders), - queryParams, - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - ListBucketResultV2 result = - Xml.unmarshal(ListBucketResultV2.class, response.body().charStream()); - return new ListObjectsV2Response(response.headers(), bucketName, region, result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do ListObjects - * version 1 S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param startAfter Fetch listing after this key (Optional). - * @param maxKeys Maximum object information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param continuationToken Continuation token (Optional). - * @param fetchOwner Flag to fetch owner information (Optional). - * @param includeUserMetadata MinIO extension flag to include user metadata (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link ListObjectsV2Response} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #listObjectsV2Async}. - */ - @Deprecated - protected ListObjectsV2Response listObjectsV2( - String bucketName, - String region, - String delimiter, - String encodingType, - String startAfter, - Integer maxKeys, - String prefix, - String continuationToken, - boolean fetchOwner, - boolean includeUserMetadata, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException, IOException { - try { - return listObjectsV2Async( - bucketName, - region, - delimiter, - encodingType, - startAfter, - maxKeys, - prefix, - continuationToken, - fetchOwner, - includeUserMetadata, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do ListObjects - * version 1 S3 API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param marker Marker (Optional). - * @param maxKeys Maximum object information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link ListObjectsV1Response}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture listObjectsV1Async( - String bucketName, - String region, - String delimiter, - String encodingType, - String marker, - Integer maxKeys, - String prefix, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = - merge( - extraQueryParams, - getCommonListObjectsQueryParams(delimiter, encodingType, maxKeys, prefix)); - if (marker != null) queryParams.put("marker", marker); - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.GET, - bucketName, - null, - location, - httpHeaders(extraHeaders), - queryParams, - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - ListBucketResultV1 result = - Xml.unmarshal(ListBucketResultV1.class, response.body().charStream()); - return new ListObjectsV1Response(response.headers(), bucketName, region, result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do ListObjects - * version 1 S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param marker Marker (Optional). - * @param maxKeys Maximum object information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link ListObjectsV1Response} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #listObjectsV1Async}. - */ - @Deprecated - protected ListObjectsV1Response listObjectsV1( - String bucketName, - String region, - String delimiter, - String encodingType, - String marker, - Integer maxKeys, - String prefix, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return listObjectsV1Async( - bucketName, - region, - delimiter, - encodingType, - marker, - maxKeys, - prefix, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do ListObjectVersions - * API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param keyMarker Key marker (Optional). - * @param maxKeys Maximum object information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param versionIdMarker Version ID marker (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link ListObjectVersionsResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture listObjectVersionsAsync( - String bucketName, - String region, - String delimiter, - String encodingType, - String keyMarker, - Integer maxKeys, - String prefix, - String versionIdMarker, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = - merge( - extraQueryParams, - getCommonListObjectsQueryParams(delimiter, encodingType, maxKeys, prefix)); - if (keyMarker != null) queryParams.put("key-marker", keyMarker); - if (versionIdMarker != null) queryParams.put("version-id-marker", versionIdMarker); - queryParams.put("versions", ""); - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.GET, - bucketName, - null, - location, - httpHeaders(extraHeaders), - queryParams, - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - ListVersionsResult result = - Xml.unmarshal(ListVersionsResult.class, response.body().charStream()); - return new ListObjectVersionsResponse( - response.headers(), bucketName, region, result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do ListObjectVersions - * API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param keyMarker Key marker (Optional). - * @param maxKeys Maximum object information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param versionIdMarker Version ID marker (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link ListObjectVersionsResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #listObjectVersionsAsync}. - */ - @Deprecated - protected ListObjectVersionsResponse listObjectVersions( - String bucketName, - String region, - String delimiter, - String encodingType, - String keyMarker, - Integer maxKeys, - String prefix, - String versionIdMarker, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return listObjectVersionsAsync( - bucketName, - region, - delimiter, - encodingType, - keyMarker, - maxKeys, - prefix, - versionIdMarker, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - private Part[] uploadParts( - PutObjectBaseArgs args, String uploadId, PartReader partReader, PartSource firstPartSource) - throws InterruptedException, ExecutionException, InsufficientDataException, InternalException, - InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { - Part[] parts = new Part[ObjectWriteArgs.MAX_MULTIPART_COUNT]; - int partNumber = 0; - PartSource partSource = firstPartSource; - while (true) { - partNumber++; - - Multimap ssecHeaders = null; - // set encryption headers in the case of SSE-C. - if (args.sse() != null && args.sse() instanceof ServerSideEncryptionCustomerKey) { - ssecHeaders = Multimaps.forMap(args.sse().headers()); - } - - UploadPartResponse response = - uploadPartAsync( - args.bucket(), - args.region(), - args.object(), - partSource, - partNumber, - uploadId, - ssecHeaders, - null) - .get(); - parts[partNumber - 1] = new Part(partNumber, response.etag()); - - partSource = partReader.getPart(); - if (partSource == null) break; - } - - return parts; - } - - private CompletableFuture putMultipartObjectAsync( - PutObjectBaseArgs args, - Multimap headers, - PartReader partReader, - PartSource firstPartSource) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return CompletableFuture.supplyAsync( - () -> { - String uploadId = null; - ObjectWriteResponse response = null; - try { - CreateMultipartUploadResponse createMultipartUploadResponse = - createMultipartUploadAsync( - args.bucket(), - args.region(), - args.object(), - headers, - args.extraQueryParams()) - .get(); - uploadId = createMultipartUploadResponse.result().uploadId(); - Part[] parts = uploadParts(args, uploadId, partReader, firstPartSource); - response = - completeMultipartUploadAsync( - args.bucket(), args.region(), args.object(), uploadId, parts, null, null) - .get(); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException - | InterruptedException - | ExecutionException e) { - Throwable throwable = e; - if (throwable instanceof ExecutionException) { - throwable = ((ExecutionException) throwable).getCause(); - } - if (throwable instanceof CompletionException) { - throwable = ((CompletionException) throwable).getCause(); - } - if (uploadId == null) { - throw new CompletionException(throwable); - } - try { - abortMultipartUploadAsync( - args.bucket(), args.region(), args.object(), uploadId, null, null) - .get(); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException - | InterruptedException - | ExecutionException ex) { - throwable = ex; - if (throwable instanceof ExecutionException) { - throwable = ((ExecutionException) throwable).getCause(); - } - if (throwable instanceof CompletionException) { - throwable = ((CompletionException) throwable).getCause(); - } - } - throw new CompletionException(throwable); - } - return response; - }); - } - - /** - * Execute put object asynchronously from object data from {@link RandomAccessFile} or {@link - * InputStream}. - * - * @param args {@link PutObjectBaseArgs}. - * @param data {@link RandomAccessFile} or {@link InputStream}. - * @param objectSize object size. - * @param partSize part size for multipart upload. - * @param partCount Number of parts for multipart upload. - * @param contentType content-type of object. - * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture putObjectAsync( - PutObjectBaseArgs args, - Object data, - long objectSize, - long partSize, - int partCount, - String contentType) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - PartReader partReader = newPartReader(data, objectSize, partSize, partCount); - if (partReader == null) { - throw new IllegalArgumentException("data must be RandomAccessFile or InputStream"); - } - - Multimap headers = newMultimap(args.extraHeaders()); - headers.putAll(args.genHeaders()); - if (!headers.containsKey("Content-Type")) headers.put("Content-Type", contentType); - - return CompletableFuture.supplyAsync( - () -> { - try { - return partReader.getPart(); - } catch (NoSuchAlgorithmException | IOException e) { - throw new CompletionException(e); - } - }) - .thenCompose( - partSource -> { - try { - if (partReader.partCount() == 1) { - return putObjectAsync( - args.bucket(), - args.region(), - args.object(), - partSource, - headers, - args.extraQueryParams()); - } else { - return putMultipartObjectAsync(args, headers, partReader, partSource); - } - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }); - } - - /** - * Do PutObject S3 - * API for {@link PartSource} asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param partSource PartSource object. - * @param headers Additional headers. - * @param extraQueryParams Additional query parameters if any. - * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - private CompletableFuture putObjectAsync( - String bucketName, - String region, - String objectName, - PartSource partSource, - Multimap headers, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.PUT, - bucketName, - objectName, - location, - httpHeaders(headers), - extraQueryParams, - partSource, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - return new ObjectWriteResponse( - response.headers(), - bucketName, - region, - objectName, - response.header("ETag").replaceAll("\"", ""), - response.header("x-amz-version-id")); - } finally { - response.close(); - } - }); - } - - /** - * Do PutObject S3 - * API asynchronously. - * - * @param bucketName Name of the bucket. - * @param objectName Object name in the bucket. - * @param data Object data must be InputStream, RandomAccessFile, byte[] or String. - * @param length Length of object data. - * @param headers Additional headers. - * @param extraQueryParams Additional query parameters if any. - * @return {@link CompletableFuture}<{@link ObjectWriteResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture putObjectAsync( - String bucketName, - String region, - String objectName, - Object data, - long length, - Multimap headers, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - if (!(data instanceof InputStream - || data instanceof RandomAccessFile - || data instanceof byte[] - || data instanceof CharSequence)) { - throw new IllegalArgumentException( - "data must be InputStream, RandomAccessFile, byte[] or String"); - } - - PartReader partReader = newPartReader(data, length, length, 1); - - if (partReader != null) { - return putObjectAsync( - bucketName, region, objectName, partReader.getPart(), headers, extraQueryParams); - } - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.PUT, - bucketName, - objectName, - location, - httpHeaders(headers), - extraQueryParams, - data, - (int) length); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - return new ObjectWriteResponse( - response.headers(), - bucketName, - region, - objectName, - response.header("ETag").replaceAll("\"", ""), - response.header("x-amz-version-id")); - } finally { - response.close(); - } - }); - } - - /** - * Do PutObject S3 - * API. - * - * @param bucketName Name of the bucket. - * @param objectName Object name in the bucket. - * @param data Object data must be InputStream, RandomAccessFile, byte[] or String. - * @param length Length of object data. - * @param headers Additional headers. - * @param extraQueryParams Additional query parameters if any. - * @return {@link ObjectWriteResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #putObjectAsync}. - */ - @Deprecated - protected ObjectWriteResponse putObject( - String bucketName, - String region, - String objectName, - Object data, - long length, - Multimap headers, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return putObjectAsync(bucketName, region, objectName, data, length, headers, extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do ListMultipartUploads - * S3 API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param keyMarker Key marker (Optional). - * @param maxUploads Maximum upload information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param uploadIdMarker Upload ID marker (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link ListMultipartUploadsResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture listMultipartUploadsAsync( - String bucketName, - String region, - String delimiter, - String encodingType, - String keyMarker, - Integer maxUploads, - String prefix, - String uploadIdMarker, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = - merge( - extraQueryParams, - newMultimap( - "uploads", - "", - "delimiter", - (delimiter != null) ? delimiter : "", - "max-uploads", - (maxUploads != null) ? maxUploads.toString() : "1000", - "prefix", - (prefix != null) ? prefix : "")); - if (encodingType != null) queryParams.put("encoding-type", encodingType); - if (keyMarker != null) queryParams.put("key-marker", keyMarker); - if (uploadIdMarker != null) queryParams.put("upload-id-marker", uploadIdMarker); - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.GET, - bucketName, - null, - location, - httpHeaders(extraHeaders), - queryParams, - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - ListMultipartUploadsResult result = - Xml.unmarshal(ListMultipartUploadsResult.class, response.body().charStream()); - return new ListMultipartUploadsResponse( - response.headers(), bucketName, region, result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do ListMultipartUploads - * S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param delimiter Delimiter (Optional). - * @param encodingType Encoding type (Optional). - * @param keyMarker Key marker (Optional). - * @param maxUploads Maximum upload information to fetch (Optional). - * @param prefix Prefix (Optional). - * @param uploadIdMarker Upload ID marker (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link ListMultipartUploadsResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #listMultipartUploadsAsync}. - */ - @Deprecated - protected ListMultipartUploadsResponse listMultipartUploads( - String bucketName, - String region, - String delimiter, - String encodingType, - String keyMarker, - Integer maxUploads, - String prefix, - String uploadIdMarker, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return listMultipartUploadsAsync( - bucketName, - region, - delimiter, - encodingType, - keyMarker, - maxUploads, - prefix, - uploadIdMarker, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do ListParts S3 - * API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Name of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param maxParts Maximum parts information to fetch (Optional). - * @param partNumberMarker Part number marker (Optional). - * @param uploadId Upload ID. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link ListPartsResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture listPartsAsync( - String bucketName, - String region, - String objectName, - Integer maxParts, - Integer partNumberMarker, - String uploadId, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = - merge( - extraQueryParams, - newMultimap( - UPLOAD_ID, - uploadId, - "max-parts", - (maxParts != null) ? maxParts.toString() : "1000")); - if (partNumberMarker != null) { - queryParams.put("part-number-marker", partNumberMarker.toString()); - } - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.GET, - bucketName, - objectName, - location, - httpHeaders(extraHeaders), - queryParams, - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - ListPartsResult result = - Xml.unmarshal(ListPartsResult.class, response.body().charStream()); - return new ListPartsResponse( - response.headers(), bucketName, region, objectName, result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do ListParts S3 - * API. - * - * @param bucketName Name of the bucket. - * @param region Name of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param maxParts Maximum parts information to fetch (Optional). - * @param partNumberMarker Part number marker (Optional). - * @param uploadId Upload ID. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link ListPartsResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #listPartsAsync}. - */ - @Deprecated - protected ListPartsResponse listParts( - String bucketName, - String region, - String objectName, - Integer maxParts, - Integer partNumberMarker, - String uploadId, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return listPartsAsync( - bucketName, - region, - objectName, - maxParts, - partNumberMarker, - uploadId, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do UploadPart S3 - * API for PartSource asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param partSource PartSource Object. - * @param partNumber Part number. - * @param uploadId Upload ID. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link UploadPartResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture uploadPartAsync( - String bucketName, - String region, - String objectName, - PartSource partSource, - int partNumber, - String uploadId, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.PUT, - bucketName, - objectName, - location, - httpHeaders(extraHeaders), - merge( - extraQueryParams, - newMultimap( - "partNumber", Integer.toString(partNumber), UPLOAD_ID, uploadId)), - partSource, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - return new UploadPartResponse( - response.headers(), - bucketName, - region, - objectName, - uploadId, - partNumber, - response.header("ETag").replaceAll("\"", "")); - } finally { - response.close(); - } - }); - } - - /** - * Do UploadPart S3 - * API asynchronously. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param data Object data must be InputStream, RandomAccessFile, byte[] or String. - * @param length Length of object data. - * @param uploadId Upload ID. - * @param partNumber Part number. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link UploadPartResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture uploadPartAsync( - String bucketName, - String region, - String objectName, - Object data, - long length, - String uploadId, - int partNumber, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - if (!(data instanceof InputStream - || data instanceof RandomAccessFile - || data instanceof byte[] - || data instanceof CharSequence)) { - throw new IllegalArgumentException( - "data must be InputStream, RandomAccessFile, byte[] or String"); - } - - PartReader partReader = newPartReader(data, length, length, 1); - - if (partReader != null) { - return uploadPartAsync( - bucketName, - region, - objectName, - partReader.getPart(), - partNumber, - uploadId, - extraHeaders, - extraQueryParams); - } - - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.PUT, - bucketName, - objectName, - location, - httpHeaders(extraHeaders), - merge( - extraQueryParams, - newMultimap( - "partNumber", Integer.toString(partNumber), UPLOAD_ID, uploadId)), - data, - (int) length); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - return new UploadPartResponse( - response.headers(), - bucketName, - region, - objectName, - uploadId, - partNumber, - response.header("ETag").replaceAll("\"", "")); - } finally { - response.close(); - } - }); - } - - /** - * Do UploadPart S3 - * API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param data Object data must be InputStream, RandomAccessFile, byte[] or String. - * @param length Length of object data. - * @param uploadId Upload ID. - * @param partNumber Part number. - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link UploadPartResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #uploadPartAsync}. - */ - @Deprecated - protected UploadPartResponse uploadPart( - String bucketName, - String region, - String objectName, - Object data, - long length, - String uploadId, - int partNumber, - Multimap extraHeaders, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return uploadPartAsync( - bucketName, - region, - objectName, - data, - length, - uploadId, - partNumber, - extraHeaders, - extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do UploadPartCopy - * S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param uploadId Upload ID. - * @param partNumber Part number. - * @param headers Request headers with source object definitions. - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link UploadPartCopyResponse} object. - * @throws ErrorResponseException thrown to indicate S3 service returned an error response. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error - * response. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - * @deprecated This method is no longer supported. Use {@link #uploadPartCopyAsync}. - */ - @Deprecated - protected UploadPartCopyResponse uploadPartCopy( - String bucketName, - String region, - String objectName, - String uploadId, - int partNumber, - Multimap headers, - Multimap extraQueryParams) - throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, - ServerException, XmlParserException, ErrorResponseException, InternalException, - InvalidResponseException { - try { - return uploadPartCopyAsync( - bucketName, region, objectName, uploadId, partNumber, headers, extraQueryParams) - .get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throwEncapsulatedException(e); - return null; - } - } - - /** - * Do UploadPartCopy - * S3 API. - * - * @param bucketName Name of the bucket. - * @param region Region of the bucket (Optional). - * @param objectName Object name in the bucket. - * @param uploadId Upload ID. - * @param partNumber Part number. - * @param headers Request headers with source object definitions. - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link UploadPartCopyResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - public CompletableFuture uploadPartCopyAsync( - String bucketName, - String region, - String objectName, - String uploadId, - int partNumber, - Multimap headers, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - return getRegionAsync(bucketName, region) - .thenCompose( - location -> { - try { - return executeAsync( - Method.PUT, - bucketName, - objectName, - location, - httpHeaders(headers), - merge( - extraQueryParams, - newMultimap( - "partNumber", Integer.toString(partNumber), "uploadId", uploadId)), - null, - 0); - } catch (InsufficientDataException - | InternalException - | InvalidKeyException - | IOException - | NoSuchAlgorithmException - | XmlParserException e) { - throw new CompletionException(e); - } - }) - .thenApply( - response -> { - try { - CopyPartResult result = - Xml.unmarshal(CopyPartResult.class, response.body().charStream()); - return new UploadPartCopyResponse( - response.headers(), - bucketName, - region, - objectName, - uploadId, - partNumber, - result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - /** - * Do ListBuckets - * S3 API. - * - * @param bucketRegion Fetch buckets from the region (Optional). - * @param maxBuckets Maximum buckets to be fetched (Optional). - * @param prefix Bucket name prefix (Optional). - * @param continuationToken continuation token (Optional). - * @param extraHeaders Extra headers for request (Optional). - * @param extraQueryParams Extra query parameters for request (Optional). - * @return {@link CompletableFuture}<{@link ListBucketsResponse}> object. - * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. - * @throws InternalException thrown to indicate internal library error. - * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. - * @throws IOException thrown to indicate I/O error on S3 operation. - * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. - * @throws XmlParserException thrown to indicate XML parsing error. - */ - protected CompletableFuture listBucketsAsync( - String bucketRegion, - Integer maxBuckets, - String prefix, - String continuationToken, - Multimap extraHeaders, - Multimap extraQueryParams) - throws InsufficientDataException, InternalException, InvalidKeyException, IOException, - NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = newMultimap(extraQueryParams); - if (bucketRegion != null) queryParams.put("bucket-region", bucketRegion); - if (maxBuckets != null) - queryParams.put("max-buckets", Integer.toString(maxBuckets > 0 ? maxBuckets : 10000)); - if (prefix != null) queryParams.put("prefix", prefix); - if (continuationToken != null) queryParams.put("continuation-token", continuationToken); - return executeGetAsync(null, extraHeaders, queryParams) - .thenApply( - response -> { - try { - ListAllMyBucketsResult result = - Xml.unmarshal(ListAllMyBucketsResult.class, response.body().charStream()); - return new ListBucketsResponse(response.headers(), result); - } catch (XmlParserException e) { - throw new CompletionException(e); - } finally { - response.close(); - } - }); - } - - @Override - public void close() throws Exception { - if (closeHttpClient) { - httpClient.dispatcher().executorService().shutdown(); - httpClient.connectionPool().evictAll(); - } - } -} diff --git a/api/src/main/java/io/minio/S3Escaper.java b/api/src/main/java/io/minio/S3Escaper.java deleted file mode 100644 index 028dd83b1..000000000 --- a/api/src/main/java/io/minio/S3Escaper.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2016 MinIO, 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 io.minio; - -import com.google.common.escape.Escaper; -import com.google.common.net.UrlEscapers; - -public class S3Escaper { - private static final Escaper ESCAPER = UrlEscapers.urlPathSegmentEscaper(); - - /** Returns S3 encoded string. */ - public static String encode(String str) { - if (str == null) { - return ""; - } - - StringBuilder builder = new StringBuilder(); - for (char ch : ESCAPER.escape(str).toCharArray()) { - switch (ch) { - case '!': - builder.append("%21"); - break; - case '$': - builder.append("%24"); - break; - case '&': - builder.append("%26"); - break; - case '\'': - builder.append("%27"); - break; - case '(': - builder.append("%28"); - break; - case ')': - builder.append("%29"); - break; - case '*': - builder.append("%2A"); - break; - case '+': - builder.append("%2B"); - break; - case ',': - builder.append("%2C"); - break; - case '/': - builder.append("%2F"); - break; - case ':': - builder.append("%3A"); - break; - case ';': - builder.append("%3B"); - break; - case '=': - builder.append("%3D"); - break; - case '@': - builder.append("%40"); - break; - case '[': - builder.append("%5B"); - break; - case ']': - builder.append("%5D"); - break; - default: - builder.append(ch); - } - } - return builder.toString(); - } - - /** Returns S3 encoded string of given path where multiple '/' are trimmed. */ - public static String encodePath(String path) { - final StringBuilder encodedPath = new StringBuilder(); - for (String pathSegment : path.split("/")) { - if (!pathSegment.isEmpty()) { - if (encodedPath.length() > 0) { - encodedPath.append("/"); - } - encodedPath.append(S3Escaper.encode(pathSegment)); - } - } - - if (path.startsWith("/")) { - encodedPath.insert(0, "/"); - } - if (path.endsWith("/")) { - encodedPath.append("/"); - } - - return encodedPath.toString(); - } -} diff --git a/api/src/main/java/io/minio/SelectObjectContentArgs.java b/api/src/main/java/io/minio/SelectObjectContentArgs.java index 684f429a4..8c1e6ba7c 100644 --- a/api/src/main/java/io/minio/SelectObjectContentArgs.java +++ b/api/src/main/java/io/minio/SelectObjectContentArgs.java @@ -22,7 +22,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#selectObjectContent} and {@link + * Arguments of {@link MinioAsyncClient#selectObjectContent} and {@link * MinioClient#selectObjectContent}. */ public class SelectObjectContentArgs extends ObjectReadArgs { @@ -61,11 +61,11 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SelectObjectContentArgs}. */ + /** Builder of {@link SelectObjectContentArgs}. */ public static final class Builder extends ObjectReadArgs.Builder { private void validateSqlExpression(String se) { - validateNotEmptyString(se, "sqlExpression"); + Utils.validateNotEmptyString(se, "sqlExpression"); } public Builder sqlExpression(String sqlExpression) { @@ -75,7 +75,7 @@ public Builder sqlExpression(String sqlExpression) { } private void validateInputSerialization(InputSerialization is) { - validateNotNull(is, "inputSerialization"); + Utils.validateNotNull(is, "inputSerialization"); } public Builder inputSerialization(InputSerialization inputSerialization) { @@ -85,7 +85,7 @@ public Builder inputSerialization(InputSerialization inputSerialization) { } private void validateOutputSerialization(OutputSerialization os) { - validateNotNull(os, "outputSerialization"); + Utils.validateNotNull(os, "outputSerialization"); } public Builder outputSerialization(OutputSerialization outputSerialization) { diff --git a/api/src/main/java/io/minio/ServerSideEncryption.java b/api/src/main/java/io/minio/ServerSideEncryption.java index c4e90cce0..373214367 100644 --- a/api/src/main/java/io/minio/ServerSideEncryption.java +++ b/api/src/main/java/io/minio/ServerSideEncryption.java @@ -16,19 +16,149 @@ package io.minio; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.minio.errors.MinioException; +import java.nio.charset.StandardCharsets; import java.util.Map; +import javax.crypto.SecretKey; +import javax.security.auth.DestroyFailedException; -/** Base class of server-side encryption. */ +/** Server-side encryption support. */ public abstract class ServerSideEncryption { - private static final Map emptyHeaders = Utils.unmodifiableMap(null); + private static final Http.Headers emptyHeaders = new Http.Headers(); - public abstract Map headers(); + public abstract Http.Headers headers(); public boolean tlsRequired() { return true; } - public Map copySourceHeaders() { + public Http.Headers copySourceHeaders() { return emptyHeaders; } + + /** S3 type of Server-side encryption. */ + public static class S3 extends ServerSideEncryption { + private static final Http.Headers headers = + new Http.Headers("X-Amz-Server-Side-Encryption", "AES256"); + + @Override + public final Http.Headers headers() { + return headers; + } + + @Override + public final boolean tlsRequired() { + return false; + } + + @Override + public String toString() { + return "SSE-S3"; + } + } + + /** KMS type of Server-side encryption. */ + public static class KMS extends ServerSideEncryption { + private static final ObjectMapper objectMapper = new ObjectMapper(); + private final Http.Headers headers; + + public KMS(String keyId, Map context) throws MinioException { + if (keyId == null) { + throw new IllegalArgumentException("Key ID cannot be null"); + } + + this.headers = + new Http.Headers( + "X-Amz-Server-Side-Encryption", + "aws:kms", + "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id", + keyId); + if (context != null) { + try { + this.headers.put( + "X-Amz-Server-Side-Encryption-Context", + Checksum.base64String( + objectMapper.writeValueAsString(context).getBytes(StandardCharsets.UTF_8))); + } catch (JsonProcessingException e) { + throw new MinioException(e); + } + } + } + + @Override + public final Http.Headers headers() { + return headers; + } + + @Override + public String toString() { + return "SSE-KMS"; + } + } + + /** Customer-key type of Server-side encryption. */ + public static class CustomerKey extends ServerSideEncryption { + private boolean isDestroyed = false; + private final SecretKey secretKey; + private final Http.Headers headers; + private final Http.Headers copySourceHeaders; + + public CustomerKey(SecretKey key) throws MinioException { + if (key == null || !key.getAlgorithm().equals("AES") || key.getEncoded().length != 32) { + throw new IllegalArgumentException("Secret key must be 256 bit AES key"); + } + + if (key.isDestroyed()) { + throw new IllegalArgumentException("Secret key already destroyed"); + } + + this.secretKey = key; + + byte[] keyBytes = key.getEncoded(); + String customerKey = Checksum.base64String(keyBytes); + String customerKeyMd5 = Checksum.base64String(Checksum.MD5.sum(keyBytes)); + + this.headers = + new Http.Headers( + "X-Amz-Server-Side-Encryption-Customer-Algorithm", "AES256", + "X-Amz-Server-Side-Encryption-Customer-Key", customerKey, + "X-Amz-Server-Side-Encryption-Customer-Key-Md5", customerKeyMd5); + + this.copySourceHeaders = + new Http.Headers( + "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm", "AES256", + "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key", customerKey, + "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5", customerKeyMd5); + } + + @Override + public final Http.Headers headers() { + if (isDestroyed) { + throw new IllegalStateException("Secret key was destroyed"); + } + + return headers; + } + + @Override + public final Http.Headers copySourceHeaders() { + if (isDestroyed) { + throw new IllegalStateException("Secret key was destroyed"); + } + + return copySourceHeaders; + } + + public final void destroy() throws DestroyFailedException { + secretKey.destroy(); + isDestroyed = true; + } + + @Override + public String toString() { + return "SSE-C"; + } + } } diff --git a/api/src/main/java/io/minio/ServerSideEncryptionCustomerKey.java b/api/src/main/java/io/minio/ServerSideEncryptionCustomerKey.java deleted file mode 100644 index 74f883c6d..000000000 --- a/api/src/main/java/io/minio/ServerSideEncryptionCustomerKey.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio; - -import com.google.common.io.BaseEncoding; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; -import javax.crypto.SecretKey; -import javax.security.auth.DestroyFailedException; - -/** Customer-key type of Server-side encryption. */ -public class ServerSideEncryptionCustomerKey extends ServerSideEncryption { - private boolean isDestroyed = false; - private final SecretKey secretKey; - private final Map headers; - private final Map copySourceHeaders; - - public ServerSideEncryptionCustomerKey(SecretKey key) - throws InvalidKeyException, NoSuchAlgorithmException { - if (key == null || !key.getAlgorithm().equals("AES") || key.getEncoded().length != 32) { - throw new IllegalArgumentException("Secret key must be 256 bit AES key"); - } - - if (key.isDestroyed()) { - throw new IllegalArgumentException("Secret key already destroyed"); - } - - this.secretKey = key; - - byte[] keyBytes = key.getEncoded(); - MessageDigest md5 = MessageDigest.getInstance("MD5"); - md5.update(keyBytes); - String customerKey = BaseEncoding.base64().encode(keyBytes); - String customerKeyMd5 = BaseEncoding.base64().encode(md5.digest()); - - Map map = new HashMap<>(); - map.put("X-Amz-Server-Side-Encryption-Customer-Algorithm", "AES256"); - map.put("X-Amz-Server-Side-Encryption-Customer-Key", customerKey); - map.put("X-Amz-Server-Side-Encryption-Customer-Key-Md5", customerKeyMd5); - this.headers = Utils.unmodifiableMap(map); - - map = new HashMap<>(); - map.put("X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm", "AES256"); - map.put("X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key", customerKey); - map.put("X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5", customerKeyMd5); - this.copySourceHeaders = Utils.unmodifiableMap(map); - } - - @Override - public final Map headers() { - if (isDestroyed) { - throw new IllegalStateException("Secret key was destroyed"); - } - - return headers; - } - - @Override - public final Map copySourceHeaders() { - if (isDestroyed) { - throw new IllegalStateException("Secret key was destroyed"); - } - - return copySourceHeaders; - } - - public final void destroy() throws DestroyFailedException { - secretKey.destroy(); - isDestroyed = true; - } - - @Override - public String toString() { - return "SSE-C"; - } -} diff --git a/api/src/main/java/io/minio/ServerSideEncryptionKms.java b/api/src/main/java/io/minio/ServerSideEncryptionKms.java deleted file mode 100644 index f3c898287..000000000 --- a/api/src/main/java/io/minio/ServerSideEncryptionKms.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -/** KMS type of Server-side encryption. */ -public class ServerSideEncryptionKms extends ServerSideEncryption { - private static final ObjectMapper objectMapper = new ObjectMapper(); - private final Map headers; - - public ServerSideEncryptionKms(String keyId, Map context) - throws JsonProcessingException { - if (keyId == null) { - throw new IllegalArgumentException("Key ID cannot be null"); - } - - Map headers = new HashMap<>(); - headers.put("X-Amz-Server-Side-Encryption", "aws:kms"); - headers.put("X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id", keyId); - if (context != null) { - headers.put( - "X-Amz-Server-Side-Encryption-Context", - Base64.getEncoder() - .encodeToString( - objectMapper.writeValueAsString(context).getBytes(StandardCharsets.UTF_8))); - } - - this.headers = Utils.unmodifiableMap(headers); - } - - @Override - public final Map headers() { - return headers; - } - - @Override - public String toString() { - return "SSE-KMS"; - } -} diff --git a/api/src/main/java/io/minio/SetBucketCorsArgs.java b/api/src/main/java/io/minio/SetBucketCorsArgs.java index 11d6b59ee..3c0d3e64a 100644 --- a/api/src/main/java/io/minio/SetBucketCorsArgs.java +++ b/api/src/main/java/io/minio/SetBucketCorsArgs.java @@ -19,9 +19,7 @@ import io.minio.messages.CORSConfiguration; import java.util.Objects; -/** - * Argument class of {@link MinioAsyncClient#setBucketCors} and {@link MinioClient#setBucketCors}. - */ +/** Arguments of {@link MinioAsyncClient#setBucketCors} and {@link MinioClient#setBucketCors}. */ public class SetBucketCorsArgs extends BucketArgs { private CORSConfiguration config; @@ -33,10 +31,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketCorsArgs}. */ + /** Builder of {@link SetBucketCorsArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateCors(CORSConfiguration config) { - validateNotNull(config, "CORS configuration"); + Utils.validateNotNull(config, "CORS configuration"); } protected void validate(SetBucketCorsArgs args) { diff --git a/api/src/main/java/io/minio/SetBucketEncryptionArgs.java b/api/src/main/java/io/minio/SetBucketEncryptionArgs.java index 3afa3d2c5..148f20538 100644 --- a/api/src/main/java/io/minio/SetBucketEncryptionArgs.java +++ b/api/src/main/java/io/minio/SetBucketEncryptionArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setBucketEncryption} and {@link + * Arguments of {@link MinioAsyncClient#setBucketEncryption} and {@link * MinioClient#setBucketEncryption}. */ public class SetBucketEncryptionArgs extends BucketArgs { @@ -34,10 +34,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketEncryptionArgs}. */ + /** Builder of {@link SetBucketEncryptionArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(SseConfiguration config) { - validateNotNull(config, "encryption configuration"); + Utils.validateNotNull(config, "encryption configuration"); } protected void validate(SetBucketEncryptionArgs args) { diff --git a/api/src/main/java/io/minio/SetBucketLifecycleArgs.java b/api/src/main/java/io/minio/SetBucketLifecycleArgs.java index ac1894888..7b43d172a 100644 --- a/api/src/main/java/io/minio/SetBucketLifecycleArgs.java +++ b/api/src/main/java/io/minio/SetBucketLifecycleArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setBucketLifecycle} and {@link + * Arguments of {@link MinioAsyncClient#setBucketLifecycle} and {@link * MinioClient#setBucketLifecycle}. */ public class SetBucketLifecycleArgs extends BucketArgs { @@ -34,10 +34,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketLifecycleArgs}. */ + /** Builder of {@link SetBucketLifecycleArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(LifecycleConfiguration config) { - validateNotNull(config, "lifecycle configuration"); + Utils.validateNotNull(config, "lifecycle configuration"); } protected void validate(SetBucketLifecycleArgs args) { diff --git a/api/src/main/java/io/minio/SetBucketNotificationArgs.java b/api/src/main/java/io/minio/SetBucketNotificationArgs.java index 189a338a9..40e9e066a 100644 --- a/api/src/main/java/io/minio/SetBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/SetBucketNotificationArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setBucketNotification} and {@link + * Arguments of {@link MinioAsyncClient#setBucketNotification} and {@link * MinioClient#setBucketNotification}. */ public class SetBucketNotificationArgs extends BucketArgs { @@ -34,10 +34,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketNotificationArgs}. */ + /** Builder of {@link SetBucketNotificationArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(NotificationConfiguration config) { - validateNotNull(config, "notification configuration"); + Utils.validateNotNull(config, "notification configuration"); } protected void validate(SetBucketNotificationArgs args) { diff --git a/api/src/main/java/io/minio/SetBucketPolicyArgs.java b/api/src/main/java/io/minio/SetBucketPolicyArgs.java index c9f454ac1..3af76a918 100644 --- a/api/src/main/java/io/minio/SetBucketPolicyArgs.java +++ b/api/src/main/java/io/minio/SetBucketPolicyArgs.java @@ -19,8 +19,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setBucketPolicy} and {@link - * MinioClient#setBucketPolicy}. + * Arguments of {@link MinioAsyncClient#setBucketPolicy} and {@link MinioClient#setBucketPolicy}. */ public class SetBucketPolicyArgs extends BucketArgs { private String config; @@ -33,10 +32,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketPolicyArgs}. */ + /** Builder of {@link SetBucketPolicyArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(String config) { - validateNotNull(config, "policy configuration"); + Utils.validateNotNull(config, "policy configuration"); } @Override diff --git a/api/src/main/java/io/minio/SetBucketReplicationArgs.java b/api/src/main/java/io/minio/SetBucketReplicationArgs.java index 5bafc4f61..15fc250ff 100644 --- a/api/src/main/java/io/minio/SetBucketReplicationArgs.java +++ b/api/src/main/java/io/minio/SetBucketReplicationArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setBucketReplication} and {@link + * Arguments of {@link MinioAsyncClient#setBucketReplication} and {@link * MinioClient#setBucketReplication}. */ public class SetBucketReplicationArgs extends BucketArgs { @@ -39,14 +39,14 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketReplicationArgs}. */ + /** Builder of {@link SetBucketReplicationArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(ReplicationConfiguration config) { - validateNotNull(config, "replication configuration"); + Utils.validateNotNull(config, "replication configuration"); } private void validateObjectLockToken(String token) { - validateNullOrNotEmptyString(token, "object lock token"); + Utils.validateNullOrNotEmptyString(token, "object lock token"); } @Override diff --git a/api/src/main/java/io/minio/SetBucketTagsArgs.java b/api/src/main/java/io/minio/SetBucketTagsArgs.java index 3dacccc7c..da4c371c8 100644 --- a/api/src/main/java/io/minio/SetBucketTagsArgs.java +++ b/api/src/main/java/io/minio/SetBucketTagsArgs.java @@ -20,9 +20,7 @@ import java.util.Map; import java.util.Objects; -/** - * Argument class of {@link MinioAsyncClient#setBucketTags} and {@link MinioClient#setBucketTags}. - */ +/** Arguments of {@link MinioAsyncClient#setBucketTags} and {@link MinioClient#setBucketTags}. */ public class SetBucketTagsArgs extends BucketArgs { private Tags tags; @@ -34,10 +32,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketTagsArgs}. */ + /** Builder of {@link SetBucketTagsArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateTags(Tags tags) { - validateNotNull(tags, "tags"); + Utils.validateNotNull(tags, "tags"); } protected void validate(SetBucketTagsArgs args) { @@ -46,7 +44,7 @@ protected void validate(SetBucketTagsArgs args) { } public Builder tags(Map map) { - validateNotNull(map, "map for tags"); + Utils.validateNotNull(map, "map for tags"); operations.add(args -> args.tags = Tags.newBucketTags(map)); return this; } diff --git a/api/src/main/java/io/minio/SetBucketVersioningArgs.java b/api/src/main/java/io/minio/SetBucketVersioningArgs.java index 2f848c994..9b9bbd3cb 100644 --- a/api/src/main/java/io/minio/SetBucketVersioningArgs.java +++ b/api/src/main/java/io/minio/SetBucketVersioningArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setBucketVersioning} and {@link + * Arguments of {@link MinioAsyncClient#setBucketVersioning} and {@link * MinioClient#setBucketVersioning}. */ public class SetBucketVersioningArgs extends BucketArgs { @@ -34,10 +34,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetBucketVersioningArgs}. */ + /** Builder of {@link SetBucketVersioningArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(VersioningConfiguration config) { - validateNotNull(config, "versioning configuration"); + Utils.validateNotNull(config, "versioning configuration"); } protected void validate(SetBucketVersioningArgs args) { diff --git a/api/src/main/java/io/minio/SetObjectLockConfigurationArgs.java b/api/src/main/java/io/minio/SetObjectLockConfigurationArgs.java index 6cef98dff..71f1a9b1d 100644 --- a/api/src/main/java/io/minio/SetObjectLockConfigurationArgs.java +++ b/api/src/main/java/io/minio/SetObjectLockConfigurationArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setObjectLockConfiguration} and {@link + * Arguments of {@link MinioAsyncClient#setObjectLockConfiguration} and {@link * MinioClient#setObjectLockConfiguration}. */ public class SetObjectLockConfigurationArgs extends BucketArgs { @@ -34,11 +34,11 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetObjectLockConfigurationArgs}. */ + /** Builder of {@link SetObjectLockConfigurationArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(ObjectLockConfiguration config) { - validateNotNull(config, "object-lock configuration"); + Utils.validateNotNull(config, "object-lock configuration"); } @Override diff --git a/api/src/main/java/io/minio/SetObjectRetentionArgs.java b/api/src/main/java/io/minio/SetObjectRetentionArgs.java index 00b363392..6f5d52bad 100644 --- a/api/src/main/java/io/minio/SetObjectRetentionArgs.java +++ b/api/src/main/java/io/minio/SetObjectRetentionArgs.java @@ -20,7 +20,7 @@ import java.util.Objects; /** - * Argument class of {@link MinioAsyncClient#setObjectRetention} and {@link + * Arguments of {@link MinioAsyncClient#setObjectRetention} and {@link * MinioClient#setObjectRetention}. */ public class SetObjectRetentionArgs extends ObjectVersionArgs { @@ -39,11 +39,11 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetObjectRetentionArgs}. */ + /** Builder of {@link SetObjectRetentionArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder { private void validateConfig(Retention config) { - validateNotNull(config, "retention configuration"); + Utils.validateNotNull(config, "retention configuration"); } protected void validate(SetObjectRetentionArgs args) { diff --git a/api/src/main/java/io/minio/SetObjectTagsArgs.java b/api/src/main/java/io/minio/SetObjectTagsArgs.java index c832d94e1..1e20bab68 100644 --- a/api/src/main/java/io/minio/SetObjectTagsArgs.java +++ b/api/src/main/java/io/minio/SetObjectTagsArgs.java @@ -20,9 +20,7 @@ import java.util.Map; import java.util.Objects; -/** - * Argument class of {@link MinioAsyncClient#setObjectTags} and {@link MinioClient#setObjectTags}. - */ +/** Arguments of {@link MinioAsyncClient#setObjectTags} and {@link MinioClient#setObjectTags}. */ public class SetObjectTagsArgs extends ObjectVersionArgs { private Tags tags; @@ -34,10 +32,10 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link SetObjectTagsArgs}. */ + /** Builder of {@link SetObjectTagsArgs}. */ public static final class Builder extends ObjectVersionArgs.Builder { private void validateTags(Tags tags) { - validateNotNull(tags, "tags"); + Utils.validateNotNull(tags, "tags"); } protected void validate(SetObjectTagsArgs args) { @@ -46,7 +44,7 @@ protected void validate(SetObjectTagsArgs args) { } public Builder tags(Map map) { - validateNotNull(map, "map for tags"); + Utils.validateNotNull(map, "map for tags"); operations.add(args -> args.tags = Tags.newObjectTags(map)); return this; } diff --git a/api/src/main/java/io/minio/Signer.java b/api/src/main/java/io/minio/Signer.java index c45f11f1a..c2ad64f95 100644 --- a/api/src/main/java/io/minio/Signer.java +++ b/api/src/main/java/io/minio/Signer.java @@ -21,6 +21,7 @@ import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import com.google.common.io.BaseEncoding; +import io.minio.errors.MinioException; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -54,16 +55,19 @@ public class Signer { // calculation. // private static final Set IGNORED_HEADERS = - ImmutableSet.of("accept-encoding", "authorization", "user-agent"); + ImmutableSet.of( + Http.Headers.ACCEPT_ENCODING.toLowerCase(Locale.US), + Http.Headers.AUTHORIZATION.toLowerCase(Locale.US), + Http.Headers.USER_AGENT.toLowerCase(Locale.US)); private static final Set PRESIGN_IGNORED_HEADERS = ImmutableSet.of( - "accept-encoding", - "authorization", - "user-agent", - "content-md5", - "x-amz-content-sha256", - "x-amz-date", - "x-amz-security-token"); + Http.Headers.ACCEPT_ENCODING.toLowerCase(Locale.US), + Http.Headers.AUTHORIZATION.toLowerCase(Locale.US), + Http.Headers.USER_AGENT.toLowerCase(Locale.US), + Http.Headers.CONTENT_MD5.toLowerCase(Locale.US), + Http.Headers.X_AMZ_CONTENT_SHA256.toLowerCase(Locale.US), + Http.Headers.X_AMZ_DATE.toLowerCase(Locale.US), + Http.Headers.X_AMZ_SECURITY_TOKEN.toLowerCase(Locale.US)); private Request request; private String contentSha256; @@ -175,7 +179,7 @@ private void setCanonicalQueryString() { Joiner.on("&").withKeyValueSeparator("=").join(signedQueryParams.entries()); } - private void setCanonicalRequest() throws NoSuchAlgorithmException { + private void setCanonicalRequest() throws MinioException { setCanonicalHeaders(IGNORED_HEADERS); this.url = this.request.url(); setCanonicalQueryString(); @@ -200,7 +204,7 @@ private void setCanonicalRequest() throws NoSuchAlgorithmException { + "\n" + this.contentSha256; - this.canonicalRequestHash = Digest.sha256Hash(this.canonicalRequest); + this.canonicalRequestHash = Checksum.hexString(Checksum.SHA256.sum(this.canonicalRequest)); } private void setStringToSign() { @@ -214,7 +218,7 @@ private void setStringToSign() { + this.canonicalRequestHash; } - private void setChunkStringToSign() throws NoSuchAlgorithmException { + private void setChunkStringToSign() throws MinioException { this.stringToSign = "AWS4-HMAC-SHA256-PAYLOAD" + "\n" @@ -224,13 +228,12 @@ private void setChunkStringToSign() throws NoSuchAlgorithmException { + "\n" + this.prevSignature + "\n" - + Digest.sha256Hash("") + + Checksum.ZERO_SHA256_HASH + "\n" + this.contentSha256; } - private void setSigningKey(String serviceName) - throws NoSuchAlgorithmException, InvalidKeyException { + private void setSigningKey(String serviceName) throws MinioException { String aws4SecretKey = "AWS4" + this.secretKey; byte[] dateKey = @@ -247,7 +250,7 @@ private void setSigningKey(String serviceName) sumHmac(dateRegionServiceKey, "aws4_request".getBytes(StandardCharsets.UTF_8)); } - private void setSignature() throws NoSuchAlgorithmException, InvalidKeyException { + private void setSignature() throws MinioException { byte[] digest = sumHmac(this.signingKey, this.stringToSign.getBytes(StandardCharsets.UTF_8)); this.signature = BaseEncoding.base16().encode(digest).toLowerCase(Locale.US); } @@ -267,7 +270,7 @@ private void setAuthorization() { /** Returns chunk signature calculated using given arguments. */ public static String getChunkSignature( String chunkSha256, ZonedDateTime date, String region, String secretKey, String prevSignature) - throws NoSuchAlgorithmException, InvalidKeyException { + throws MinioException { Signer signer = new Signer(null, chunkSha256, date, region, null, secretKey, prevSignature); signer.setScope("s3"); signer.setChunkStringToSign(); @@ -285,8 +288,9 @@ private static Request signV4( String accessKey, String secretKey, String contentSha256) - throws NoSuchAlgorithmException, InvalidKeyException { - ZonedDateTime date = ZonedDateTime.parse(request.header("x-amz-date"), Time.AMZ_DATE_FORMAT); + throws MinioException { + ZonedDateTime date = + ZonedDateTime.parse(request.header(Http.Headers.X_AMZ_DATE), Time.AMZ_DATE_FORMAT); Signer signer = new Signer(request, contentSha256, date, region, accessKey, secretKey, null); signer.setScope(serviceName); @@ -296,37 +300,38 @@ private static Request signV4( signer.setSignature(); signer.setAuthorization(); - return request.newBuilder().header("Authorization", signer.authorization).build(); + return request.newBuilder().header(Http.Headers.AUTHORIZATION, signer.authorization).build(); } /** Returns signed request of given request for S3 service. */ public static Request signV4S3( Request request, String region, String accessKey, String secretKey, String contentSha256) - throws NoSuchAlgorithmException, InvalidKeyException { + throws MinioException { return signV4("s3", request, region, accessKey, secretKey, contentSha256); } /** Returns signed request of given request for STS service. */ public static Request signV4Sts( Request request, String region, String accessKey, String secretKey, String contentSha256) - throws NoSuchAlgorithmException, InvalidKeyException { + throws MinioException { return signV4("sts", request, region, accessKey, secretKey, contentSha256); } - private void setPresignCanonicalRequest(int expires) throws NoSuchAlgorithmException { + private void setPresignCanonicalRequest(int expires) throws MinioException { setCanonicalHeaders(PRESIGN_IGNORED_HEADERS); HttpUrl.Builder urlBuilder = this.request.url().newBuilder(); urlBuilder.addEncodedQueryParameter( - S3Escaper.encode("X-Amz-Algorithm"), S3Escaper.encode("AWS4-HMAC-SHA256")); + Utils.encode("X-Amz-Algorithm"), Utils.encode("AWS4-HMAC-SHA256")); urlBuilder.addEncodedQueryParameter( - S3Escaper.encode("X-Amz-Credential"), S3Escaper.encode(this.accessKey + "/" + this.scope)); + Utils.encode("X-Amz-Credential"), Utils.encode(this.accessKey + "/" + this.scope)); urlBuilder.addEncodedQueryParameter( - S3Escaper.encode("X-Amz-Date"), S3Escaper.encode(this.date.format(Time.AMZ_DATE_FORMAT))); + Utils.encode(Http.Headers.X_AMZ_DATE), + Utils.encode(this.date.format(Time.AMZ_DATE_FORMAT))); urlBuilder.addEncodedQueryParameter( - S3Escaper.encode("X-Amz-Expires"), S3Escaper.encode(Integer.toString(expires))); + Utils.encode("X-Amz-Expires"), Utils.encode(Integer.toString(expires))); urlBuilder.addEncodedQueryParameter( - S3Escaper.encode("X-Amz-SignedHeaders"), S3Escaper.encode(this.signedHeaders)); + Utils.encode("X-Amz-SignedHeaders"), Utils.encode(this.signedHeaders)); this.url = urlBuilder.build(); setCanonicalQueryString(); @@ -344,7 +349,7 @@ private void setPresignCanonicalRequest(int expires) throws NoSuchAlgorithmExcep + "\n" + this.contentSha256; - this.canonicalRequestHash = Digest.sha256Hash(this.canonicalRequest); + this.canonicalRequestHash = Checksum.hexString(Checksum.SHA256.sum(this.canonicalRequest)); } /** @@ -353,11 +358,12 @@ private void setPresignCanonicalRequest(int expires) throws NoSuchAlgorithmExcep */ public static HttpUrl presignV4( Request request, String region, String accessKey, String secretKey, int expires) - throws NoSuchAlgorithmException, InvalidKeyException { - String contentSha256 = "UNSIGNED-PAYLOAD"; - ZonedDateTime date = ZonedDateTime.parse(request.header("x-amz-date"), Time.AMZ_DATE_FORMAT); + throws MinioException { + ZonedDateTime date = + ZonedDateTime.parse(request.header(Http.Headers.X_AMZ_DATE), Time.AMZ_DATE_FORMAT); - Signer signer = new Signer(request, contentSha256, date, region, accessKey, secretKey, null); + Signer signer = + new Signer(request, Checksum.UNSIGNED_PAYLOAD, date, region, accessKey, secretKey, null); signer.setScope("s3"); signer.setPresignCanonicalRequest(expires); signer.setStringToSign(); @@ -367,8 +373,7 @@ public static HttpUrl presignV4( return signer .url .newBuilder() - .addEncodedQueryParameter( - S3Escaper.encode("X-Amz-Signature"), S3Escaper.encode(signer.signature)) + .addEncodedQueryParameter(Utils.encode("X-Amz-Signature"), Utils.encode(signer.signature)) .build(); } @@ -385,23 +390,23 @@ public static String credential(String accessKey, ZonedDateTime date, String reg /** Returns pre-signed post policy string for given stringToSign, secret key, date and region. */ public static String postPresignV4( String stringToSign, String secretKey, ZonedDateTime date, String region) - throws NoSuchAlgorithmException, InvalidKeyException { + throws MinioException { Signer signer = new Signer(null, null, date, region, null, secretKey, null); signer.stringToSign = stringToSign; signer.setSigningKey("s3"); signer.setSignature(); - return signer.signature; } /** Returns HMacSHA256 digest of given key and data. */ - public static byte[] sumHmac(byte[] key, byte[] data) - throws NoSuchAlgorithmException, InvalidKeyException { - Mac mac = Mac.getInstance("HmacSHA256"); - - mac.init(new SecretKeySpec(key, "HmacSHA256")); - mac.update(data); - - return mac.doFinal(); + public static byte[] sumHmac(byte[] key, byte[] data) throws MinioException { + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key, "HmacSHA256")); + mac.update(data); + return mac.doFinal(); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new MinioException(e); + } } } diff --git a/api/src/main/java/io/minio/SourceObject.java b/api/src/main/java/io/minio/SourceObject.java new file mode 100644 index 000000000..5d00d427e --- /dev/null +++ b/api/src/main/java/io/minio/SourceObject.java @@ -0,0 +1,93 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import io.minio.errors.InternalException; +import java.util.Objects; + +/** A source object definition for {@link ComposeObjectArgs} and {@link CopyObjectArgs}. */ +public class SourceObject extends ObjectConditionalReadArgs { + private Long objectSize = null; + + protected SourceObject() {} + + public SourceObject(SourceObject args, long objectSize, String etag) { + super(args, etag); + validateSize(objectSize); + this.objectSize = objectSize; + } + + private void throwException(long objectsize, long arg, String argName) { + StringBuilder builder = + new StringBuilder().append("source ").append(bucketName).append("/").append(objectName); + + if (versionId != null) builder.append("?versionId=").append(versionId); + + builder + .append(": ") + .append(argName) + .append(" ") + .append(arg) + .append(" is beyond object size ") + .append(objectSize); + + throw new IllegalArgumentException(builder.toString()); + } + + private void validateSize(long objectSize) { + if (offset != null && offset >= objectSize) throwException(objectSize, offset, "offset"); + + if (length != null) { + if (length > objectSize) throwException(objectSize, length, "length"); + long composeSize = (offset == null ? 0 : offset) + length; + if (composeSize > objectSize) throwException(objectSize, composeSize, "compose size"); + } + } + + public Long objectSize() { + return objectSize; + } + + public Http.Headers headers() throws InternalException { + if (this.objectSize == null) { + throw new InternalException("SourceObject must be created with object size", null); + } + return makeCopyHeaders(); + } + + public static Builder builder() { + return new Builder(); + } + + /** Argument builder of {@link SourceObject}. */ + public static final class Builder + extends ObjectConditionalReadArgs.Builder {} + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SourceObject)) return false; + if (!super.equals(o)) return false; + SourceObject that = (SourceObject) o; + return Objects.equals(objectSize, that.objectSize); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), objectSize); + } +} diff --git a/api/src/main/java/io/minio/StatObjectArgs.java b/api/src/main/java/io/minio/StatObjectArgs.java index 522b4c540..c8b277637 100644 --- a/api/src/main/java/io/minio/StatObjectArgs.java +++ b/api/src/main/java/io/minio/StatObjectArgs.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,25 +16,14 @@ package io.minio; -/** Argument class of {@link MinioAsyncClient#statObject} and {@link MinioClient#statObject}. */ -public class StatObjectArgs extends ObjectConditionalReadArgs { +/** Arguments of {@link MinioAsyncClient#statObject} and {@link MinioClient#statObject}. */ +public class StatObjectArgs extends HeadObjectBaseArgs { protected StatObjectArgs() {} - public StatObjectArgs(ObjectReadArgs args) { - this.extraHeaders = args.extraHeaders; - this.extraQueryParams = args.extraQueryParams; - this.bucketName = args.bucketName; - this.region = args.region; - this.objectName = args.objectName; - this.versionId = args.versionId; - this.ssec = args.ssec; - } - public static Builder builder() { return new Builder(); } - /** Argument builder of {@link StatObjectArgs}. */ - public static final class Builder - extends ObjectConditionalReadArgs.Builder {} + /** Builder of {@link StatObjectArgs}. */ + public static final class Builder extends HeadObjectBaseArgs.Builder {} } diff --git a/api/src/main/java/io/minio/StatObjectResponse.java b/api/src/main/java/io/minio/StatObjectResponse.java index 85cf8fe1e..a266d3b4d 100644 --- a/api/src/main/java/io/minio/StatObjectResponse.java +++ b/api/src/main/java/io/minio/StatObjectResponse.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,113 +16,9 @@ package io.minio; -import io.minio.messages.LegalHold; -import io.minio.messages.ResponseDate; -import io.minio.messages.RetentionMode; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import okhttp3.Headers; - -/** Response of {@link S3Base#statObjectAsync}. */ -public class StatObjectResponse extends GenericResponse { - private String etag; - private long size; - private ZonedDateTime lastModified; - private RetentionMode retentionMode; - private ZonedDateTime retentionRetainUntilDate; - private LegalHold legalHold; - private boolean deleteMarker; - private Map userMetadata; - - public StatObjectResponse(Headers headers, String bucket, String region, String object) { - super(headers, bucket, region, object); - String value; - - value = headers.get("ETag"); - this.etag = (value != null ? value.replaceAll("\"", "") : ""); - - value = headers.get("Content-Length"); - this.size = (value != null ? Long.parseLong(value) : -1); - - this.lastModified = - ZonedDateTime.parse(headers.get("Last-Modified"), Time.HTTP_HEADER_DATE_FORMAT); - - value = headers.get("x-amz-object-lock-mode"); - this.retentionMode = (value != null ? RetentionMode.valueOf(value) : null); - - value = headers.get("x-amz-object-lock-retain-until-date"); - this.retentionRetainUntilDate = - (value != null ? ResponseDate.fromString(value).zonedDateTime() : null); - - this.legalHold = new LegalHold("ON".equals(headers.get("x-amz-object-lock-legal-hold"))); - - this.deleteMarker = Boolean.parseBoolean(headers.get("x-amz-delete-marker")); - - Map userMetadata = new HashMap<>(); - for (String key : headers.names()) { - if (key.toLowerCase(Locale.US).startsWith("x-amz-meta-")) { - userMetadata.put( - key.toLowerCase(Locale.US).substring("x-amz-meta-".length(), key.length()), - headers.get(key)); - } - } - - this.userMetadata = Utils.unmodifiableMap(userMetadata); - } - - public String etag() { - return etag; - } - - public long size() { - return size; - } - - public ZonedDateTime lastModified() { - return lastModified; - } - - public RetentionMode retentionMode() { - return retentionMode; - } - - public ZonedDateTime retentionRetainUntilDate() { - return retentionRetainUntilDate; - } - - public LegalHold legalHold() { - return legalHold; - } - - public boolean deleteMarker() { - return deleteMarker; - } - - public String versionId() { - return this.headers().get("x-amz-version-id"); - } - - public String contentType() { - return this.headers().get("Content-Type"); - } - - public Map userMetadata() { - return userMetadata; - } - - @Override - public String toString() { - return "ObjectStat{" - + "bucket=" - + bucket() - + ", object=" - + object() - + ", last-modified=" - + lastModified - + ", size=" - + size - + "}"; +/** Response of {@link MinioAsyncClient#statObject}. */ +public class StatObjectResponse extends HeadObjectResponse { + public StatObjectResponse(HeadObjectResponse response) { + super(response.headers(), response.bucket(), response.region(), response.object()); } } diff --git a/api/src/main/java/io/minio/Time.java b/api/src/main/java/io/minio/Time.java index 01b788f68..06cfc75bf 100644 --- a/api/src/main/java/io/minio/Time.java +++ b/api/src/main/java/io/minio/Time.java @@ -17,9 +17,18 @@ package io.minio; +import com.fasterxml.jackson.annotation.JsonCreator; import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; import java.util.Locale; +import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; +import org.simpleframework.xml.convert.Converter; +import org.simpleframework.xml.stream.InputNode; +import org.simpleframework.xml.stream.OutputNode; /** Time formatters for S3 APIs. */ public class Time { @@ -28,7 +37,7 @@ public class Time { public static final DateTimeFormatter AMZ_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'", Locale.US).withZone(UTC); - public static final DateTimeFormatter RESPONSE_DATE_FORMAT = + public static final DateTimeFormatter ISO8601UTC_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH':'mm':'ss'.'SSS'Z'", Locale.US).withZone(UTC); // Formatted string is convertible to LocalDate only, not to LocalDateTime or ZonedDateTime. @@ -40,7 +49,54 @@ public class Time { public static final DateTimeFormatter HTTP_HEADER_DATE_FORMAT = DateTimeFormatter.ofPattern("EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'", Locale.US).withZone(UTC); - public static final DateTimeFormatter EXPIRATION_DATE_FORMAT = RESPONSE_DATE_FORMAT; - private Time() {} + + /** Wrapped {@link ZonedDateTime} to handle ISO8601UTC format. */ + @Root + @Convert(S3Time.S3TimeConverter.class) + public static class S3Time { + // ISO8601UTC format handles 0 or more digits of fraction-of-second + private static final DateTimeFormatter FORMAT = + new DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd'T'HH':'mm':'ss") + .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) + .appendPattern("'Z'") + .toFormatter(Locale.US) + .withZone(UTC); + + private ZonedDateTime value; + + public S3Time() {} + + public S3Time(ZonedDateTime value) { + this.value = value; + } + + public ZonedDateTime toZonedDateTime() { + return value; + } + + @Override + public String toString() { + return value == null ? null : value.format(ISO8601UTC_FORMAT); + } + + @JsonCreator + public static S3Time fromString(String value) { + return new S3Time(ZonedDateTime.parse(value, FORMAT)); + } + + /** XML converter class. */ + public static class S3TimeConverter implements Converter { + @Override + public S3Time read(InputNode node) throws Exception { + return S3Time.fromString(node.getValue()); + } + + @Override + public void write(OutputNode node, S3Time time) { + node.setValue(time.toString()); + } + } + } } diff --git a/api/src/main/java/io/minio/UploadObjectArgs.java b/api/src/main/java/io/minio/UploadObjectArgs.java index 68775b184..5bce3b0f2 100644 --- a/api/src/main/java/io/minio/UploadObjectArgs.java +++ b/api/src/main/java/io/minio/UploadObjectArgs.java @@ -16,12 +16,14 @@ package io.minio; +import io.minio.errors.MinioException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Objects; +import okhttp3.MediaType; -/** Argument class of {@link MinioAsyncClient#uploadObject} and {@link MinioClient#uploadObject}. */ +/** Arguments of {@link MinioAsyncClient#uploadObject} and {@link MinioClient#uploadObject}. */ public class UploadObjectArgs extends PutObjectBaseArgs { private String filename; @@ -29,27 +31,18 @@ public String filename() { return filename; } - /** - * Gets content type. It returns if content type is set (or) value of "Content-Type" header (or) - * probed content type of file (or) default "application/octet-stream". - */ - public String contentType() throws IOException { - String contentType = super.contentType(); - if (contentType != null) { - return contentType; - } - - contentType = Files.probeContentType(Paths.get(filename)); - return (contentType != null && !contentType.isEmpty()) - ? contentType - : "application/octet-stream"; + public MediaType contentType() throws IOException { + MediaType contentType = super.contentType(); + if (contentType != null) return contentType; + String type = Files.probeContentType(Paths.get(filename)); + return type != null ? MediaType.parse(type) : null; } public static Builder builder() { return new Builder(); } - /** Argument builder of {@link UploadObjectArgs}. */ + /** Builder of {@link UploadObjectArgs}. */ public static final class Builder extends PutObjectBaseArgs.Builder { @Override protected void validate(UploadObjectArgs args) { @@ -58,36 +51,34 @@ protected void validate(UploadObjectArgs args) { } private void validateFilename(String filename) { - validateNotEmptyString(filename, "filename"); + Utils.validateNotEmptyString(filename, "filename"); if (!Files.isRegularFile(Paths.get(filename))) { throw new IllegalArgumentException(filename + " not a regular file"); } } - public Builder filename(String filename, long partSize) throws IOException { - validateFilename(filename); - final long objectSize = Files.size(Paths.get(filename)); - - long[] partinfo = getPartInfo(objectSize, partSize); - final long pSize = partinfo[0]; - final int partCount = (int) partinfo[1]; - - operations.add(args -> args.filename = filename); - operations.add(args -> args.objectSize = objectSize); - operations.add(args -> args.partSize = pSize); - operations.add(args -> args.partCount = partCount); - return this; + public Builder filename(String filename, long partSize) throws MinioException { + try { + validateFilename(filename); + final long objectSize = Files.size(Paths.get(filename)); + + long[] partinfo = getPartInfo(objectSize, partSize); + final long pSize = partinfo[0]; + final int partCount = (int) partinfo[1]; + + operations.add(args -> args.filename = filename); + operations.add(args -> args.objectSize = objectSize); + operations.add(args -> args.partSize = pSize); + operations.add(args -> args.partCount = partCount); + return this; + } catch (IOException e) { + throw new MinioException(e); + } } - public Builder filename(String filename) throws IOException { + public Builder filename(String filename) throws MinioException { return this.filename(filename, 0); } - - public Builder contentType(String contentType) { - validateContentType(contentType); - operations.add(args -> args.contentType = contentType); - return this; - } } @Override diff --git a/api/src/main/java/io/minio/UploadPartArgs.java b/api/src/main/java/io/minio/UploadPartArgs.java new file mode 100644 index 000000000..3af55b536 --- /dev/null +++ b/api/src/main/java/io/minio/UploadPartArgs.java @@ -0,0 +1,92 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#uploadPart}. */ +public class UploadPartArgs extends PutObjectAPIBaseArgs { + private String uploadId; + private int partNumber; + + protected UploadPartArgs() {} + + public UploadPartArgs( + PutObjectBaseArgs args, + String uploadId, + int partNumber, + ByteBuffer buffer, + Http.Headers checksumHeaders) { + super(args, buffer, checksumHeaders); + this.uploadId = uploadId; + this.partNumber = partNumber; + this.buffer = buffer; + if (args.sse() != null && args.sse() instanceof ServerSideEncryption.CustomerKey) { + this.headers.putAll(args.sse().headers()); + } + } + + public String uploadId() { + return uploadId; + } + + public int partNumber() { + return partNumber; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link UploadPartArgs}. */ + public static final class Builder extends PutObjectAPIBaseArgs.Builder { + @Override + protected void validate(UploadPartArgs args) { + super.validate(args); + Utils.validateNotEmptyString(args.uploadId, "upload ID"); + if (args.partNumber <= 0) { + throw new IllegalArgumentException("valid part number must be provided"); + } + } + + public Builder uploadId(String uploadId) { + Utils.validateNotEmptyString(uploadId, "upload ID"); + operations.add(args -> args.uploadId = uploadId); + return this; + } + + public Builder partNumber(int partNumber) { + if (partNumber <= 0) throw new IllegalArgumentException("valid part number must be provided"); + operations.add(args -> args.partNumber = partNumber); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UploadPartArgs)) return false; + if (!super.equals(o)) return false; + UploadPartArgs that = (UploadPartArgs) o; + return Objects.equals(uploadId, that.uploadId) && partNumber == that.partNumber; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), uploadId, partNumber); + } +} diff --git a/api/src/main/java/io/minio/UploadPartCopyArgs.java b/api/src/main/java/io/minio/UploadPartCopyArgs.java new file mode 100644 index 000000000..8da88ec4c --- /dev/null +++ b/api/src/main/java/io/minio/UploadPartCopyArgs.java @@ -0,0 +1,99 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio; + +import java.util.Objects; + +/** Arguments of {@link BaseS3Client#uploadPartCopy}. */ +public class UploadPartCopyArgs extends ObjectArgs { + private String uploadId; + private int partNumber; + private Http.Headers headers; + + private UploadPartCopyArgs() {} + + public UploadPartCopyArgs( + ComposeObjectArgs args, String uploadId, int partNumber, Http.Headers headers) { + super(args); + this.uploadId = uploadId; + this.partNumber = partNumber; + this.headers = headers; + } + + public String uploadId() { + return uploadId; + } + + public int partNumber() { + return partNumber; + } + + public Http.Headers headers() { + return headers; + } + + public static Builder builder() { + return new Builder(); + } + + /** Builder of {@link UploadPartCopyArgs}. */ + public static final class Builder extends ObjectArgs.Builder { + @Override + protected void validate(UploadPartCopyArgs args) { + super.validate(args); + Utils.validateNotEmptyString(args.uploadId, "upload ID"); + if (args.partNumber <= 0) { + throw new IllegalArgumentException("valid part number must be provided"); + } + Utils.validateNotNull(args.headers, "headers"); + } + + public Builder uploadId(String uploadId) { + Utils.validateNotEmptyString(uploadId, "upload ID"); + operations.add(args -> args.uploadId = uploadId); + return this; + } + + public Builder partNumber(int partNumber) { + if (partNumber <= 0) throw new IllegalArgumentException("valid part number must be provided"); + operations.add(args -> args.partNumber = partNumber); + return this; + } + + public Builder headers(Http.Headers headers) { + Utils.validateNotNull(headers, "headers"); + operations.add(args -> args.headers = headers); + return this; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UploadPartCopyArgs)) return false; + if (!super.equals(o)) return false; + UploadPartCopyArgs that = (UploadPartCopyArgs) o; + return Objects.equals(uploadId, that.uploadId) + && Objects.equals(partNumber, that.partNumber) + && Objects.equals(headers, that.headers); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), uploadId, partNumber, headers); + } +} diff --git a/api/src/main/java/io/minio/UploadPartCopyResponse.java b/api/src/main/java/io/minio/UploadPartCopyResponse.java index 6f1651ade..7e2cfe08d 100644 --- a/api/src/main/java/io/minio/UploadPartCopyResponse.java +++ b/api/src/main/java/io/minio/UploadPartCopyResponse.java @@ -17,9 +17,10 @@ package io.minio; import io.minio.messages.CopyPartResult; +import io.minio.messages.Part; import okhttp3.Headers; -/** Response class of {@link S3Base#uploadPartCopyAsync}. */ +/** Response of {@link BaseS3Client#uploadPartCopy}. */ public class UploadPartCopyResponse extends GenericResponse { private String uploadId; private int partNumber; @@ -50,4 +51,8 @@ public int partNumber() { public CopyPartResult result() { return result; } + + public Part part() { + return new Part(result, partNumber); + } } diff --git a/api/src/main/java/io/minio/UploadPartResponse.java b/api/src/main/java/io/minio/UploadPartResponse.java index 7d42661d2..cbcb01262 100644 --- a/api/src/main/java/io/minio/UploadPartResponse.java +++ b/api/src/main/java/io/minio/UploadPartResponse.java @@ -16,13 +16,13 @@ package io.minio; +import io.minio.messages.Part; import okhttp3.Headers; -/** Response class of {@link S3Base#uploadPartAsync}. */ +/** Response of {@link BaseS3Client#uploadPart}. */ public class UploadPartResponse extends GenericResponse { private String uploadId; - private int partNumber; - private String etag; + private Part part; public UploadPartResponse( Headers headers, @@ -34,19 +34,22 @@ public UploadPartResponse( String etag) { super(headers, bucket, region, object); this.uploadId = uploadId; - this.partNumber = partNumber; - this.etag = etag; + this.part = + new Part( + partNumber, + etag, + headers.get("x-amz-checksum-crc32"), + headers.get("x-amz-checksum-crc32c"), + headers.get("x-amz-checksum-crc64nvme"), + headers.get("x-amz-checksum-sha1"), + headers.get("x-amz-checksum-sha256")); } public String uploadId() { return uploadId; } - public int partNumber() { - return partNumber; - } - - public String etag() { - return etag; + public Part part() { + return part; } } diff --git a/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java b/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java index 25b13751d..bf606f2ab 100644 --- a/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java +++ b/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java @@ -21,7 +21,7 @@ import java.util.Random; /** - * Argument class of {@link MinioAsyncClient#uploadSnowballObjects} and {@link + * Arguments of {@link MinioAsyncClient#uploadSnowballObjects} and {@link * MinioClient#uploadSnowballObjects}. */ public class UploadSnowballObjectsArgs extends ObjectWriteArgs { @@ -47,11 +47,11 @@ public static Builder builder() { return new Builder(); } - /** Argument builder of {@link UploadSnowballObjectsArgs}. */ + /** Builder of {@link UploadSnowballObjectsArgs}. */ public static final class Builder extends ObjectWriteArgs.Builder { private void validateObjects(Iterable objects) { - validateNotNull(objects, "objects"); + Utils.validateNotNull(objects, "objects"); } @Override diff --git a/api/src/main/java/io/minio/Utils.java b/api/src/main/java/io/minio/Utils.java index 1fe65c140..f9d6e7df0 100644 --- a/api/src/main/java/io/minio/Utils.java +++ b/api/src/main/java/io/minio/Utils.java @@ -16,19 +16,141 @@ package io.minio; +import com.google.common.escape.Escaper; +import com.google.common.net.UrlEscapers; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.net.URL; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import okhttp3.HttpUrl; /** Collection of utility functions. */ public class Utils { + private static final Escaper ESCAPER = UrlEscapers.urlPathSegmentEscaper(); + public static final String UTF_8 = StandardCharsets.UTF_8.toString(); + public static final String AWS_S3_PREFIX = + "^(((bucket\\.|accesspoint\\.)" + + "vpce(-(?!_)[a-z_\\d]+(? T validateNotNull(T arg, String argName) { + return Objects.requireNonNull(arg, argName + " must not be null"); + } + + public static void validateNotEmptyString(String arg, String argName) { + validateNotNull(arg, argName); + if (arg.isEmpty()) { + throw new IllegalArgumentException(argName + " must be a non-empty string."); + } + } + + public static void validateNullOrNotEmptyString(String arg, String argName) { + if (arg != null && arg.isEmpty()) { + throw new IllegalArgumentException(argName + " must be a non-empty string."); + } + } + + public static boolean isValidIPv4OrIPv6(String value) { + return InetAddressValidator.getInstance().isValid(value); + } + + public static boolean isValidIPv6(String value) { + return InetAddressValidator.getInstance().isValidInet6Address(value); + } + + public static boolean isValidIPv4(String value) { + return InetAddressValidator.getInstance().isValidInet4Address(value); + } + + public static void validateHostnameOrIPAddress(String endpoint) { + if (isValidIPv4OrIPv6(endpoint)) return; + + if (!HOSTNAME_REGEX.matcher(endpoint).find()) { + throw new IllegalArgumentException("invalid hostname " + endpoint); + } + } + + public static void validateUrl(HttpUrl url) { + if (!url.encodedPath().equals("/")) { + throw new IllegalArgumentException("no path allowed in endpoint " + url); + } + } + + public static HttpUrl getBaseUrl(String endpoint) { + validateNotEmptyString(endpoint, "endpoint"); + HttpUrl url = HttpUrl.parse(endpoint); + if (url == null) { + validateHostnameOrIPAddress(endpoint); + url = new HttpUrl.Builder().scheme("https").host(endpoint).build(); + } else { + validateUrl(url); + } + + return url; + } + + public static String getHostHeader(HttpUrl url) { + String host = url.host(); + if (isValidIPv6(host)) host = "[" + host + "]"; + + // ignore port when port and service matches i.e HTTP -> 80, HTTPS -> 443 + if ((url.scheme().equals("http") && url.port() == 80) + || (url.scheme().equals("https") && url.port() == 443)) { + return host; + } + + return host + ":" + url.port(); + } + public static String urlDecode(String value, String type) { if (!"url".equals(type)) return value; try { @@ -46,4 +168,593 @@ public static List unmodifiableList(List value) { public static Map unmodifiableMap(Map value) { return Collections.unmodifiableMap(value == null ? new HashMap() : value); } + + public static String stringify(Object value) { + if (value == null) return ""; + + if (value.getClass().isArray()) { + StringBuilder result = new StringBuilder("["); + + int length = Array.getLength(value); + + if (value.getClass().getComponentType().isPrimitive()) { + for (int i = 0; i < length; i++) { + if (i > 0) result.append(", "); + result.append(Array.get(value, i)); + } + } else { + for (int i = 0; i < length; i++) { + if (i > 0) result.append(", "); + Object element = Array.get(value, i); + result.append(stringify(element)); + } + } + + result.append("]"); + return result.toString(); + } + + if (value instanceof CharSequence) { + return "'" + value.toString() + "'"; + } + + return value.toString(); + } + + /** Returns S3 encoded string. */ + public static String encode(String str) { + if (str == null) { + return ""; + } + + StringBuilder builder = new StringBuilder(); + for (char ch : ESCAPER.escape(str).toCharArray()) { + switch (ch) { + case '!': + builder.append("%21"); + break; + case '$': + builder.append("%24"); + break; + case '&': + builder.append("%26"); + break; + case '\'': + builder.append("%27"); + break; + case '(': + builder.append("%28"); + break; + case ')': + builder.append("%29"); + break; + case '*': + builder.append("%2A"); + break; + case '+': + builder.append("%2B"); + break; + case ',': + builder.append("%2C"); + break; + case '/': + builder.append("%2F"); + break; + case ':': + builder.append("%3A"); + break; + case ';': + builder.append("%3B"); + break; + case '=': + builder.append("%3D"); + break; + case '@': + builder.append("%40"); + break; + case '[': + builder.append("%5B"); + break; + case ']': + builder.append("%5D"); + break; + default: + builder.append(ch); + } + } + return builder.toString(); + } + + /** Returns S3 encoded string of given path where multiple '/' are trimmed. */ + public static String encodePath(String path) { + final StringBuilder encodedPath = new StringBuilder(); + for (String pathSegment : path.split("/")) { + if (!pathSegment.isEmpty()) { + if (encodedPath.length() > 0) { + encodedPath.append("/"); + } + encodedPath.append(Utils.encode(pathSegment)); + } + } + + if (path.startsWith("/")) encodedPath.insert(0, "/"); + if (path.endsWith("/")) encodedPath.append("/"); + + return encodedPath.toString(); + } + + public static CompletableFuture failedFuture(Throwable throwable) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(throwable); + return future; + } + + public static String getDefaultUserAgent() { + return String.format( + "MinIO (%s; %s) minio-java/%s", + System.getProperty("os.name"), + System.getProperty("os.arch"), + MinioProperties.INSTANCE.getVersion()); + } + + /** Identifies and stores version information of minio-java package at run time. */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "MS_EXPOSE_REP") + public static enum MinioProperties { + INSTANCE; + + private static final Logger LOGGER = Logger.getLogger(MinioProperties.class.getName()); + + private final AtomicReference version = new AtomicReference<>(null); + + public String getVersion() { + String result = version.get(); + if (result != null) { + return result; + } + setVersion(); + return version.get(); + } + + private synchronized void setVersion() { + if (version.get() != null) { + return; + } + version.set("dev"); + ClassLoader classLoader = getClass().getClassLoader(); + if (classLoader == null) { + return; + } + + try { + Enumeration resources = classLoader.getResources("META-INF/MANIFEST.MF"); + while (resources.hasMoreElements()) { + try (InputStream is = resources.nextElement().openStream()) { + Manifest manifest = new Manifest(is); + if ("minio".equals(manifest.getMainAttributes().getValue("Implementation-Title"))) { + version.set(manifest.getMainAttributes().getValue("Implementation-Version")); + return; + } + } + } + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "IOException occurred", e); + version.set("unknown"); + } + } + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + + /** + * Regular Expression validation (using JDK 1.4+ regex support). + * + *

Construct the validator either for a single regular expression or a set (array) of regular + * expressions. By default validation is case sensitive but constructors are provided to + * allow case in-sensitive validation. For example to create a validator which does case + * in-sensitive validation for a set of regular expressions: + * + *

+   * 
+   * String[] regexs = new String[] {...};
+   * RegexValidator validator = new RegexValidator(regexs, false);
+   * 
+   * 
+ * + *

+ * + *

    + *
  • Validate true or false: + *
  • + *
      + *
    • boolean valid = validator.isValid(value); + *
    + *
  • Validate returning an aggregated String of the matched groups: + *
  • + *
      + *
    • String result = validator.validate(value); + *
    + *
  • Validate returning the matched groups: + *
  • + *
      + *
    • String[] result = validator.match(value); + *
    + *
+ * + *

Note that patterns are matched against the entire input. + * + *

+ * + *

Cached instances pre-compile and re-use {@link Pattern}(s) - which according to the {@link + * Pattern} API are safe to use in a multi-threaded environment. + * + * @version $Revision$ + * @since Validator 1.4 + */ + public static class RegexValidator implements Serializable { + + private static final long serialVersionUID = -8832409930574867162L; + + private final Pattern[] patterns; + + /** + * Construct a case sensitive validator for a single regular expression. + * + * @param regex The regular expression this validator will validate against + */ + public RegexValidator(String regex) { + this(regex, true); + } + + /** + * Construct a validator for a single regular expression with the specified case sensitivity. + * + * @param regex The regular expression this validator will validate against + * @param caseSensitive when true matching is case sensitive, otherwise + * matching is case in-sensitive + */ + public RegexValidator(String regex, boolean caseSensitive) { + this(new String[] {regex}, caseSensitive); + } + + /** + * Construct a case sensitive validator that matches any one of the set of regular + * expressions. + * + * @param regexs The set of regular expressions this validator will validate against + */ + public RegexValidator(String[] regexs) { + this(regexs, true); + } + + /** + * Construct a validator that matches any one of the set of regular expressions with the + * specified case sensitivity. + * + * @param regexs The set of regular expressions this validator will validate against + * @param caseSensitive when true matching is case sensitive, otherwise + * matching is case in-sensitive + */ + public RegexValidator(String[] regexs, boolean caseSensitive) { + if (regexs == null || regexs.length == 0) { + throw new IllegalArgumentException("Regular expressions are missing"); + } + patterns = new Pattern[regexs.length]; + int flags = (caseSensitive ? 0 : Pattern.CASE_INSENSITIVE); + for (int i = 0; i < regexs.length; i++) { + if (regexs[i] == null || regexs[i].length() == 0) { + throw new IllegalArgumentException("Regular expression[" + i + "] is missing"); + } + patterns[i] = Pattern.compile(regexs[i], flags); + } + } + + /** + * Validate a value against the set of regular expressions. + * + * @param value The value to validate. + * @return true if the value is valid otherwise false. + */ + public boolean isValid(String value) { + if (value == null) { + return false; + } + for (int i = 0; i < patterns.length; i++) { + if (patterns[i].matcher(value).matches()) { + return true; + } + } + return false; + } + + /** + * Validate a value against the set of regular expressions returning the array of matched + * groups. + * + * @param value The value to validate. + * @return String array of the groups matched if valid or null if invalid + */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "PZLA", + justification = "Null is checked, not empty array. API is clear as well.") + public String[] match(String value) { + if (value == null) { + return null; + } + for (int i = 0; i < patterns.length; i++) { + Matcher matcher = patterns[i].matcher(value); + if (matcher.matches()) { + int count = matcher.groupCount(); + String[] groups = new String[count]; + for (int j = 0; j < count; j++) { + groups[j] = matcher.group(j + 1); + } + return groups; + } + } + return null; + } + + /** + * Validate a value against the set of regular expressions returning a String value of the + * aggregated groups. + * + * @param value The value to validate. + * @return Aggregated String value comprised of the groups matched if valid or null + * if invalid + */ + public String validate(String value) { + if (value == null) { + return null; + } + for (int i = 0; i < patterns.length; i++) { + Matcher matcher = patterns[i].matcher(value); + if (matcher.matches()) { + int count = matcher.groupCount(); + if (count == 1) { + return matcher.group(1); + } + StringBuilder buffer = new StringBuilder(); + for (int j = 0; j < count; j++) { + String component = matcher.group(j + 1); + if (component != null) { + buffer.append(component); + } + } + return buffer.toString(); + } + } + return null; + } + + /** + * Provide a String representation of this validator. + * + * @return A String representation of this validator + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("RegexValidator{"); + for (int i = 0; i < patterns.length; i++) { + if (i > 0) { + buffer.append(","); + } + buffer.append(patterns[i].pattern()); + } + buffer.append("}"); + return buffer.toString(); + } + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + + /** + * InetAddress validation and conversion routines (java.net.InetAddress). + * + *

+ * + *

+ * + *

This class provides methods to validate a candidate IP address. + * + *

+ * + *

This class is a Singleton; you can retrieve the instance via the {@link #getInstance()} + * method. + * + * @version $Revision$ + * @since Validator 1.4 + */ + public static class InetAddressValidator { + + private static final int IPV4_MAX_OCTET_VALUE = 255; + + private static final int MAX_UNSIGNED_SHORT = 0xffff; + + private static final int BASE_16 = 16; + + private static final long serialVersionUID = -919201640201914789L; + + private static final String IPV4_REGEX = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"; + + // Max number of hex groups (separated by :) in an IPV6 address + private static final int IPV6_MAX_HEX_GROUPS = 8; + + // Max hex digits in each IPv6 group + private static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4; + + /** Singleton instance of this class. */ + private static final InetAddressValidator VALIDATOR = new InetAddressValidator(); + + /** IPv4 RegexValidator. */ + private final RegexValidator ipv4Validator = new RegexValidator(IPV4_REGEX); + + private InetAddressValidator() {} + + /** + * Returns the singleton instance of this validator. + * + * @return the singleton instance of this validator + */ + public static InetAddressValidator getInstance() { + return VALIDATOR; + } + + /** + * Checks if the specified string is a valid IP address. + * + * @param inetAddress the string to validate + * @return true if the string validates as an IP address + */ + public boolean isValid(String inetAddress) { + return isValidInet4Address(inetAddress) || isValidInet6Address(inetAddress); + } + + /** + * Validates an IPv4 address. Returns true if valid. + * + * @param inet4Address the IPv4 address to validate + * @return true if the argument contains a valid IPv4 address + */ + public boolean isValidInet4Address(String inet4Address) { + // verify that address conforms to generic IPv4 format + String[] groups = ipv4Validator.match(inet4Address); + + if (groups == null) { + return false; + } + + // verify that address subgroups are legal + for (String ipSegment : groups) { + if (ipSegment == null || ipSegment.length() == 0) { + return false; + } + + int iIpSegment = 0; + + try { + iIpSegment = Integer.parseInt(ipSegment); + } catch (NumberFormatException e) { + return false; + } + + if (iIpSegment > IPV4_MAX_OCTET_VALUE) { + return false; + } + + if (ipSegment.length() > 1 && ipSegment.startsWith("0")) { + return false; + } + } + + return true; + } + + /** + * Validates an IPv6 address. Returns true if valid. + * + * @param inet6Address the IPv6 address to validate + * @return true if the argument contains a valid IPv6 address + * @since 1.4.1 + */ + public boolean isValidInet6Address(String inet6Address) { + boolean containsCompressedZeroes = inet6Address.contains("::"); + if (containsCompressedZeroes + && inet6Address.indexOf("::") != inet6Address.lastIndexOf("::")) { + return false; + } + if (inet6Address.startsWith(":") && !inet6Address.startsWith("::") + || inet6Address.endsWith(":") && !inet6Address.endsWith("::")) { + return false; + } + String[] octets = inet6Address.split(":"); + if (containsCompressedZeroes) { + List octetList = new ArrayList(Arrays.asList(octets)); + if (inet6Address.endsWith("::")) { + // String.split() drops ending empty segments + octetList.add(""); + } else if (inet6Address.startsWith("::") && !octetList.isEmpty()) { + octetList.remove(0); + } + octets = octetList.toArray(new String[octetList.size()]); + } + if (octets.length > IPV6_MAX_HEX_GROUPS) { + return false; + } + int validOctets = 0; + int emptyOctets = 0; + for (int index = 0; index < octets.length; index++) { + String octet = octets[index]; + if (octet.length() == 0) { + emptyOctets++; + if (emptyOctets > 1) { + return false; + } + } else { + emptyOctets = 0; + if (octet.contains(".")) { // contains is Java 1.5+ + if (!inet6Address.endsWith(octet)) { + return false; + } + if (index > octets.length - 1 || index > 6) { // CHECKSTYLE IGNORE MagicNumber + // IPV4 occupies last two octets + return false; + } + if (!isValidInet4Address(octet)) { + return false; + } + validOctets += 2; + continue; + } + if (octet.length() > IPV6_MAX_HEX_DIGITS_PER_GROUP) { + return false; + } + int octetInt = 0; + try { + octetInt = Integer.valueOf(octet, BASE_16).intValue(); + } catch (NumberFormatException e) { + return false; + } + if (octetInt < 0 || octetInt > MAX_UNSIGNED_SHORT) { + return false; + } + } + validOctets++; + } + if (validOctets < IPV6_MAX_HEX_GROUPS && !containsCompressedZeroes) { + return false; + } + return true; + } + } } diff --git a/api/src/main/java/io/minio/credentials/AssumeRoleProvider.java b/api/src/main/java/io/minio/credentials/AssumeRoleProvider.java index b94496994..44f8ec264 100644 --- a/api/src/main/java/io/minio/credentials/AssumeRoleProvider.java +++ b/api/src/main/java/io/minio/credentials/AssumeRoleProvider.java @@ -16,11 +16,12 @@ package io.minio.credentials; -import io.minio.Digest; +import io.minio.Checksum; +import io.minio.Http; import io.minio.Signer; import io.minio.Time; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import io.minio.Utils; +import io.minio.errors.MinioException; import java.security.ProviderException; import java.time.ZonedDateTime; import java.util.Objects; @@ -41,7 +42,7 @@ * href="https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html">AssumeRole * API. */ -public class AssumeRoleProvider extends AssumeRoleBaseProvider { +public class AssumeRoleProvider extends BaseIdentityProvider { private final String accessKey; private final String secretKey; private final String region; @@ -59,7 +60,7 @@ public AssumeRoleProvider( @Nullable String roleSessionName, @Nullable String externalId, @Nullable OkHttpClient customHttpClient) - throws NoSuchAlgorithmException { + throws MinioException { super(customHttpClient); stsEndpoint = Objects.requireNonNull(stsEndpoint, "STS endpoint cannot be empty"); HttpUrl url = Objects.requireNonNull(HttpUrl.parse(stsEndpoint), "Invalid STS endpoint"); @@ -75,13 +76,6 @@ public AssumeRoleProvider( throw new IllegalArgumentException("Length of ExternalId must be in between 2 and 1224"); } - String host = url.host() + ":" + url.port(); - // ignore port when port and service matches i.e HTTP -> 80, HTTPS -> 443 - if ((url.scheme().equals("http") && url.port() == 80) - || (url.scheme().equals("https") && url.port() == 443)) { - host = url.host(); - } - HttpUrl.Builder urlBuilder = newUrlBuilder( url, @@ -95,11 +89,11 @@ public AssumeRoleProvider( } String data = urlBuilder.build().encodedQuery(); - this.contentSha256 = Digest.sha256Hash(data); + this.contentSha256 = Checksum.hexString(Checksum.SHA256.sum(data)); this.request = new Request.Builder() .url(url) - .header("Host", host) + .header(Http.Headers.HOST, Utils.getHostHeader(url)) .method( "POST", RequestBody.create(data, MediaType.parse("application/x-www-form-urlencoded"))) @@ -112,26 +106,30 @@ protected Request getRequest() { return Signer.signV4Sts( this.request .newBuilder() - .header("x-amz-date", ZonedDateTime.now().format(Time.AMZ_DATE_FORMAT)) + .header(Http.Headers.X_AMZ_DATE, ZonedDateTime.now().format(Time.AMZ_DATE_FORMAT)) .build(), region, accessKey, secretKey, contentSha256); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { + } catch (MinioException e) { throw new ProviderException("Signature calculation failed", e); } } @Override - protected Class getResponseClass() { - return AssumeRoleResponse.class; + protected Class getResponseClass() { + return Response.class; } - /** Object representation of response XML of AssumeRole API. */ + /** + * Response XML of AssumeRole + * API. + */ @Root(name = "AssumeRoleResponse", strict = false) @Namespace(reference = "https://sts.amazonaws.com/doc/2011-06-15/") - public static class AssumeRoleResponse implements AssumeRoleBaseProvider.Response { + public static class Response implements BaseIdentityProvider.Response { @Path(value = "AssumeRoleResult") @Element(name = "Credentials") private Credentials credentials; diff --git a/api/src/main/java/io/minio/credentials/AwsConfigProvider.java b/api/src/main/java/io/minio/credentials/AwsConfigProvider.java index 2a2e594d3..0eb95c556 100644 --- a/api/src/main/java/io/minio/credentials/AwsConfigProvider.java +++ b/api/src/main/java/io/minio/credentials/AwsConfigProvider.java @@ -16,12 +16,12 @@ package io.minio.credentials; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Paths; import java.security.ProviderException; import java.util.HashMap; @@ -54,23 +54,17 @@ public AwsConfigProvider(@Nullable String filename, @Nullable String profile) { */ @Override public Credentials fetch() { - String filename = this.filename; - if (filename == null) { - filename = getProperty("AWS_SHARED_CREDENTIALS_FILE"); - } + String filename = + this.filename != null ? this.filename : getProperty("AWS_SHARED_CREDENTIALS_FILE"); if (filename == null) { filename = Paths.get(System.getProperty("user.home"), ".aws", "credentials").toString(); } String profile = this.profile; - if (profile == null) { - profile = getProperty("AWS_PROFILE"); - } - if (profile == null) { - profile = "default"; - } + if (profile == null) profile = getProperty("AWS_PROFILE"); + if (profile == null) profile = "default"; - try (InputStream is = new FileInputStream(filename)) { + try (InputStream is = Files.newInputStream(Paths.get(filename))) { Map result = unmarshal(new InputStreamReader(is, StandardCharsets.UTF_8)); Properties values = result.get(profile); if (values == null) { diff --git a/api/src/main/java/io/minio/credentials/AssumeRoleBaseProvider.java b/api/src/main/java/io/minio/credentials/BaseIdentityProvider.java similarity index 82% rename from api/src/main/java/io/minio/credentials/AssumeRoleBaseProvider.java rename to api/src/main/java/io/minio/credentials/BaseIdentityProvider.java index becc81b8e..75c98ce2d 100644 --- a/api/src/main/java/io/minio/credentials/AssumeRoleBaseProvider.java +++ b/api/src/main/java/io/minio/credentials/BaseIdentityProvider.java @@ -17,9 +17,9 @@ package io.minio.credentials; import io.minio.Xml; +import io.minio.errors.MinioException; import io.minio.errors.XmlParserException; import java.io.IOException; -import java.security.GeneralSecurityException; import java.security.ProviderException; import java.util.Arrays; import java.util.concurrent.TimeUnit; @@ -30,13 +30,16 @@ import okhttp3.Protocol; import okhttp3.Request; -/** Base class to AssumeRole based providers. */ -public abstract class AssumeRoleBaseProvider implements Provider { +/** + * Base provider of {@link LdapIdentityProvider}, {@link CertificateIdentityProvider}, {@link + * WebIdentityClientGrantsProvider} and {@link AssumeRoleProvider}. + */ +public abstract class BaseIdentityProvider implements Provider { public static final int DEFAULT_DURATION_SECONDS = (int) TimeUnit.HOURS.toSeconds(1); private final OkHttpClient httpClient; private Credentials credentials; - public AssumeRoleBaseProvider(OkHttpClient customHttpClient) { + public BaseIdentityProvider(OkHttpClient customHttpClient) { // HTTP/1.1 is only supported in default client because of HTTP/2 in OkHttpClient cause 5 // minutes timeout on program exit. this.httpClient = @@ -45,11 +48,11 @@ public AssumeRoleBaseProvider(OkHttpClient customHttpClient) { : new OkHttpClient().newBuilder().protocols(Arrays.asList(Protocol.HTTP_1_1)).build(); } - public AssumeRoleBaseProvider( + public BaseIdentityProvider( OkHttpClient customHttpClient, SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) - throws GeneralSecurityException, IOException { + throws MinioException { if (customHttpClient != null) { if (sslSocketFactory != null || trustManager != null) { throw new IllegalArgumentException( @@ -76,9 +79,7 @@ public AssumeRoleBaseProvider( @Override public synchronized Credentials fetch() { - if (credentials != null && !credentials.isExpired()) { - return credentials; - } + if (credentials != null && !credentials.isExpired()) return credentials; try (okhttp3.Response response = httpClient.newCall(getRequest()).execute()) { if (!response.isSuccessful()) { @@ -114,17 +115,9 @@ protected HttpUrl.Builder newUrlBuilder( urlBuilder.addQueryParameter("DurationSeconds", String.valueOf(durationSeconds)); } - if (policy != null) { - urlBuilder.addQueryParameter("Policy", policy); - } - - if (roleArn != null) { - urlBuilder.addQueryParameter("RoleArn", roleArn); - } - - if (roleSessionName != null) { - urlBuilder.addQueryParameter("RoleSessionName", roleSessionName); - } + if (policy != null) urlBuilder.addQueryParameter("Policy", policy); + if (roleArn != null) urlBuilder.addQueryParameter("RoleArn", roleArn); + if (roleSessionName != null) urlBuilder.addQueryParameter("RoleSessionName", roleSessionName); return urlBuilder; } @@ -137,8 +130,9 @@ protected Credentials parseResponse(okhttp3.Response response) protected abstract Request getRequest(); - protected abstract Class getResponseClass(); + protected abstract Class getResponseClass(); + /** Response to get credentials of {@link BaseIdentityProvider}. */ public static interface Response { public Credentials getCredentials(); } diff --git a/api/src/main/java/io/minio/credentials/CertificateIdentityProvider.java b/api/src/main/java/io/minio/credentials/CertificateIdentityProvider.java index 5fb1afebe..71fe13ef0 100644 --- a/api/src/main/java/io/minio/credentials/CertificateIdentityProvider.java +++ b/api/src/main/java/io/minio/credentials/CertificateIdentityProvider.java @@ -16,8 +16,7 @@ package io.minio.credentials; -import java.io.IOException; -import java.security.GeneralSecurityException; +import io.minio.errors.MinioException; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -38,7 +37,7 @@ * href="https://github.com/minio/minio/blob/master/docs/sts/tls.md">AssumeRoleWithCertificate * API. */ -public class CertificateIdentityProvider extends AssumeRoleBaseProvider { +public class CertificateIdentityProvider extends BaseIdentityProvider { private static final RequestBody EMPTY_BODY = RequestBody.create(new byte[] {}, MediaType.parse("application/octet-stream")); private final Request request; @@ -49,7 +48,7 @@ public CertificateIdentityProvider( @Nullable X509TrustManager trustManager, @Nullable Integer durationSeconds, @Nullable OkHttpClient customHttpClient) - throws GeneralSecurityException, IOException { + throws MinioException { super(customHttpClient, sslSocketFactory, trustManager); stsEndpoint = Objects.requireNonNull(stsEndpoint, "STS endpoint cannot be empty"); HttpUrl url = Objects.requireNonNull(HttpUrl.parse(stsEndpoint), "Invalid STS endpoint"); @@ -75,14 +74,18 @@ protected Request getRequest() { } @Override - protected Class getResponseClass() { - return CertificateIdentityResponse.class; + protected Class getResponseClass() { + return Response.class; } - /** Object representation of response XML of AssumeRoleWithCertificate API. */ + /** + * Response XML of AssumeRoleWithCertificate + * API. + */ @Root(name = "AssumeRoleWithCertificateResponse", strict = false) @Namespace(reference = "https://sts.amazonaws.com/doc/2011-06-15/") - public static class CertificateIdentityResponse implements AssumeRoleBaseProvider.Response { + public static class Response implements BaseIdentityProvider.Response { @Path(value = "AssumeRoleWithCertificateResult") @Element(name = "Credentials") private Credentials credentials; diff --git a/api/src/main/java/io/minio/credentials/ChainedProvider.java b/api/src/main/java/io/minio/credentials/ChainedProvider.java index 92af16550..46e2af325 100644 --- a/api/src/main/java/io/minio/credentials/ChainedProvider.java +++ b/api/src/main/java/io/minio/credentials/ChainedProvider.java @@ -33,9 +33,7 @@ public ChainedProvider(@Nonnull Provider... providers) { @Override public synchronized Credentials fetch() { - if (credentials != null && !credentials.isExpired()) { - return credentials; - } + if (credentials != null && !credentials.isExpired()) return credentials; if (currentProvider != null) { try { diff --git a/api/src/main/java/io/minio/credentials/ClientGrantsProvider.java b/api/src/main/java/io/minio/credentials/ClientGrantsProvider.java index 9e1c80747..2c808ee6a 100644 --- a/api/src/main/java/io/minio/credentials/ClientGrantsProvider.java +++ b/api/src/main/java/io/minio/credentials/ClientGrantsProvider.java @@ -55,14 +55,18 @@ protected HttpUrl.Builder newUrlBuilder(Jwt jwt) { } @Override - protected Class getResponseClass() { - return ClientGrantsResponse.class; + protected Class getResponseClass() { + return Response.class; } - /** Object representation of response XML of AssumeRoleWithClientGrants API. */ + /** + * Response XML of AssumeRoleWithClientGrants + * API. + */ @Root(name = "AssumeRoleWithClientGrantsResponse", strict = false) @Namespace(reference = "https://sts.amazonaws.com/doc/2011-06-15/") - public static class ClientGrantsResponse implements AssumeRoleBaseProvider.Response { + public static class Response implements BaseIdentityProvider.Response { @Path(value = "AssumeRoleWithClientGrantsResult") @Element(name = "Credentials") private Credentials credentials; diff --git a/api/src/main/java/io/minio/credentials/Credentials.java b/api/src/main/java/io/minio/credentials/Credentials.java index fb28da816..136f1f9fd 100644 --- a/api/src/main/java/io/minio/credentials/Credentials.java +++ b/api/src/main/java/io/minio/credentials/Credentials.java @@ -18,7 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.minio.messages.ResponseDate; +import io.minio.Time; import java.time.Duration; import java.time.ZonedDateTime; import java.util.Objects; @@ -27,7 +27,7 @@ import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; -/** Object representation of credentials access key, secret key and session token. */ +/** Credentials contains access key, secret key and session token. */ @Root(name = "Credentials", strict = false) @JsonIgnoreProperties(ignoreUnknown = true) public class Credentials { @@ -45,13 +45,13 @@ public class Credentials { @Element(name = "Expiration") @JsonProperty("expiration") - private final ResponseDate expiration; + private final Time.S3Time expiration; public Credentials( @Nonnull @Element(name = "AccessKeyId") @JsonProperty("accessKey") String accessKey, @Nonnull @Element(name = "SecretAccessKey") @JsonProperty("secretKey") String secretKey, @Nullable @Element(name = "SessionToken") @JsonProperty("sessionToken") String sessionToken, - @Nullable @Element(name = "Expiration") @JsonProperty("expiration") ResponseDate expiration) { + @Nullable @Element(name = "Expiration") @JsonProperty("expiration") Time.S3Time expiration) { this.accessKey = Objects.requireNonNull(accessKey, "AccessKey must not be null"); this.secretKey = Objects.requireNonNull(secretKey, "SecretKey must not be null"); if (accessKey.isEmpty() || secretKey.isEmpty()) { @@ -73,11 +73,12 @@ public String sessionToken() { return sessionToken; } - public boolean isExpired() { - if (expiration == null) { - return false; - } + public ZonedDateTime expiration() { + return expiration == null ? null : expiration.toZonedDateTime(); + } - return ZonedDateTime.now().plus(Duration.ofSeconds(10)).isAfter(expiration.zonedDateTime()); + public boolean isExpired() { + if (expiration == null) return false; + return ZonedDateTime.now().plus(Duration.ofSeconds(10)).isAfter(expiration.toZonedDateTime()); } } diff --git a/api/src/main/java/io/minio/credentials/EnvironmentProvider.java b/api/src/main/java/io/minio/credentials/EnvironmentProvider.java index 6b500f6c1..80ec3f79e 100644 --- a/api/src/main/java/io/minio/credentials/EnvironmentProvider.java +++ b/api/src/main/java/io/minio/credentials/EnvironmentProvider.java @@ -19,7 +19,10 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Base class of credential providers using environment variables. */ +/** + * Base environment provider of {@link AwsConfigProvider}, {@link MinioClientConfigProvider}, {@link + * AwsEnvironmentProvider}, {@link MinioEnvironmentProvider} and {@link IamAwsProvider}. + */ public abstract class EnvironmentProvider implements Provider { /** Get value of a property from system property or environment variable. */ @Nullable diff --git a/api/src/main/java/io/minio/credentials/IamAwsProvider.java b/api/src/main/java/io/minio/credentials/IamAwsProvider.java index 08abb1050..74accf59e 100644 --- a/api/src/main/java/io/minio/credentials/IamAwsProvider.java +++ b/api/src/main/java/io/minio/credentials/IamAwsProvider.java @@ -21,7 +21,8 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; -import io.minio.messages.ResponseDate; +import io.minio.Http; +import io.minio.Time; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -200,9 +201,7 @@ private HttpUrl getIamRoleNamedUrl(String token) { @Override public synchronized Credentials fetch() { - if (credentials != null && !credentials.isExpired()) { - return credentials; - } + if (credentials != null && !credentials.isExpired()) return credentials; HttpUrl url = this.customEndpoint; String tokenFile = getProperty("AWS_WEB_IDENTITY_TOKEN_FILE"); @@ -211,7 +210,7 @@ public synchronized Credentials fetch() { return credentials; } - String tokenHeader = "Authorization"; + String tokenHeader = Http.Headers.AUTHORIZATION; String token = getProperty("AWS_CONTAINER_AUTHORIZATION_TOKEN"); if (getProperty("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") != null) { if (url == null) { @@ -223,9 +222,7 @@ public synchronized Credentials fetch() { .build(); } } else if (getProperty("AWS_CONTAINER_CREDENTIALS_FULL_URI") != null) { - if (url == null) { - url = HttpUrl.parse(getProperty("AWS_CONTAINER_CREDENTIALS_FULL_URI")); - } + if (url == null) url = HttpUrl.parse(getProperty("AWS_CONTAINER_CREDENTIALS_FULL_URI")); checkLoopbackHost(url); } else { token = fetchImdsToken(); @@ -237,6 +234,7 @@ public synchronized Credentials fetch() { return credentials; } + /** ECS Credentials of {@link IamAwsProvider}. */ public static class EcsCredentials { @JsonProperty("AccessKeyID") private String accessKey; @@ -248,7 +246,7 @@ public static class EcsCredentials { private String sessionToken; @JsonProperty("Expiration") - private ResponseDate expiration; + private Time.S3Time expiration; @JsonProperty("Code") private String code; diff --git a/api/src/main/java/io/minio/credentials/Jwt.java b/api/src/main/java/io/minio/credentials/Jwt.java index 86088059e..0475ebfcd 100644 --- a/api/src/main/java/io/minio/credentials/Jwt.java +++ b/api/src/main/java/io/minio/credentials/Jwt.java @@ -21,7 +21,7 @@ import java.util.Objects; import javax.annotation.Nonnull; -/** JSON web token used in WebIdentity and ClientGrants providers. */ +/** JSON web token used in {@link WebIdentityProvider} and {@link ClientGrantsProvider}. */ public class Jwt { @JsonProperty("access_token") private final String token; diff --git a/api/src/main/java/io/minio/credentials/LdapIdentityProvider.java b/api/src/main/java/io/minio/credentials/LdapIdentityProvider.java index 14b21cde7..b601e7d0b 100644 --- a/api/src/main/java/io/minio/credentials/LdapIdentityProvider.java +++ b/api/src/main/java/io/minio/credentials/LdapIdentityProvider.java @@ -34,7 +34,7 @@ * href="https://github.com/minio/minio/blob/master/docs/sts/ldap.md">AssumeRoleWithLDAPIdentity * API. */ -public class LdapIdentityProvider extends AssumeRoleBaseProvider { +public class LdapIdentityProvider extends BaseIdentityProvider { private static final RequestBody EMPTY_BODY = RequestBody.create(new byte[] {}, MediaType.parse("application/octet-stream")); private final Request request; @@ -84,14 +84,18 @@ protected Request getRequest() { } @Override - protected Class getResponseClass() { - return LdapIdentityResponse.class; + protected Class getResponseClass() { + return Response.class; } - /** Object representation of response XML of AssumeRoleWithLDAPIdentity API. */ + /** + * Response XML of AssumeRoleWithLDAPIdentity + * API. + */ @Root(name = "AssumeRoleWithLDAPIdentityResponse", strict = false) @Namespace(reference = "https://sts.amazonaws.com/doc/2011-06-15/") - public static class LdapIdentityResponse implements AssumeRoleBaseProvider.Response { + public static class Response implements BaseIdentityProvider.Response { @Path(value = "AssumeRoleWithLDAPIdentityResult") @Element(name = "Credentials") private Credentials credentials; diff --git a/api/src/main/java/io/minio/credentials/MinioClientConfigProvider.java b/api/src/main/java/io/minio/credentials/MinioClientConfigProvider.java index fee406209..c45c885d7 100644 --- a/api/src/main/java/io/minio/credentials/MinioClientConfigProvider.java +++ b/api/src/main/java/io/minio/credentials/MinioClientConfigProvider.java @@ -20,11 +20,11 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Paths; import java.security.ProviderException; import java.util.Locale; @@ -62,30 +62,26 @@ public MinioClientConfigProvider(@Nullable String filename, @Nullable String ali */ @Override public Credentials fetch() { - String filename = this.filename; + String filename = + this.filename != null ? this.filename : getProperty("MINIO_SHARED_CREDENTIALS_FILE"); if (filename == null) { - filename = getProperty("MINIO_SHARED_CREDENTIALS_FILE"); - } - if (filename == null) { - String mcDir = ".mc"; - if (System.getProperty("os.name").toLowerCase(Locale.US).contains("windows")) { - mcDir = "mc"; - } - - filename = Paths.get(System.getProperty("user.home"), mcDir, "config.json").toString(); + filename = + Paths.get( + System.getProperty("user.home"), + System.getProperty("os.name").toLowerCase(Locale.US).contains("windows") + ? "mc" + : ".mc", + "config.json") + .toString(); } String alias = this.alias; - if (alias == null) { - alias = getProperty("MINIO_ALIAS"); - } - if (alias == null) { - alias = "s3"; - } + if (alias == null) alias = getProperty("MINIO_ALIAS"); + if (alias == null) alias = "s3"; - try (InputStream is = new FileInputStream(filename)) { - McConfig config = - mapper.readValue(new InputStreamReader(is, StandardCharsets.UTF_8), McConfig.class); + try (InputStream is = Files.newInputStream(Paths.get(filename))) { + Config config = + mapper.readValue(new InputStreamReader(is, StandardCharsets.UTF_8), Config.class); Map values = config.get(alias); if (values == null) { throw new ProviderException( @@ -111,10 +107,11 @@ public Credentials fetch() { } } + /** Configuration of {@link MinioClientConfigProvider}. */ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value = {"UwF", "UuF"}, justification = "All the fields are written at the time of JSON unmarshalling.") - public static class McConfig { + public static class Config { private Map> hosts; public Map get(String alias) { diff --git a/api/src/main/java/io/minio/credentials/Provider.java b/api/src/main/java/io/minio/credentials/Provider.java index 4540534d6..4aa459b5d 100644 --- a/api/src/main/java/io/minio/credentials/Provider.java +++ b/api/src/main/java/io/minio/credentials/Provider.java @@ -25,7 +25,7 @@ public interface Provider { /** * Returns a valid {@link Credentials} instance by retrieving from credential provider service if - * neccessary. + * necessary. */ Credentials fetch(); } diff --git a/api/src/main/java/io/minio/credentials/StaticProvider.java b/api/src/main/java/io/minio/credentials/StaticProvider.java index e0b227fce..66f8efdfe 100644 --- a/api/src/main/java/io/minio/credentials/StaticProvider.java +++ b/api/src/main/java/io/minio/credentials/StaticProvider.java @@ -19,7 +19,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Fixed credential provider. */ +/** Provider contains constant credentials. */ public class StaticProvider implements Provider { private final Credentials credentials; diff --git a/api/src/main/java/io/minio/credentials/WebIdentityClientGrantsProvider.java b/api/src/main/java/io/minio/credentials/WebIdentityClientGrantsProvider.java index d3e3e3b11..7c4bd3486 100644 --- a/api/src/main/java/io/minio/credentials/WebIdentityClientGrantsProvider.java +++ b/api/src/main/java/io/minio/credentials/WebIdentityClientGrantsProvider.java @@ -27,8 +27,8 @@ import okhttp3.Request; import okhttp3.RequestBody; -/** Base class of WebIdentity and ClientGrants providers. */ -public abstract class WebIdentityClientGrantsProvider extends AssumeRoleBaseProvider { +/** Base provider of {@link WebIdentityProvider} and {@link ClientGrantsProvider}. */ +public abstract class WebIdentityClientGrantsProvider extends BaseIdentityProvider { public static final int MIN_DURATION_SECONDS = (int) TimeUnit.MINUTES.toSeconds(15); public static final int MAX_DURATION_SECONDS = (int) TimeUnit.DAYS.toSeconds(7); private static final RequestBody EMPTY_BODY = @@ -59,18 +59,9 @@ public WebIdentityClientGrantsProvider( } protected int getDurationSeconds(int expiry) { - if (durationSeconds != null && durationSeconds > 0) { - expiry = durationSeconds; - } - - if (expiry > MAX_DURATION_SECONDS) { - return MAX_DURATION_SECONDS; - } - - if (expiry <= 0) { - return expiry; - } - + if (durationSeconds != null && durationSeconds > 0) expiry = durationSeconds; + if (expiry > MAX_DURATION_SECONDS) return MAX_DURATION_SECONDS; + if (expiry <= 0) return expiry; return (expiry < MIN_DURATION_SECONDS) ? MIN_DURATION_SECONDS : expiry; } diff --git a/api/src/main/java/io/minio/credentials/WebIdentityProvider.java b/api/src/main/java/io/minio/credentials/WebIdentityProvider.java index 787be1b62..108af80bf 100644 --- a/api/src/main/java/io/minio/credentials/WebIdentityProvider.java +++ b/api/src/main/java/io/minio/credentials/WebIdentityProvider.java @@ -60,14 +60,18 @@ protected HttpUrl.Builder newUrlBuilder(Jwt jwt) { } @Override - protected Class getResponseClass() { - return WebIdentityResponse.class; + protected Class getResponseClass() { + return Response.class; } - /** Object representation of response XML of AssumeRoleWithWebIdentity API. */ + /** + * Response XML AssumeRoleWithWebIdentity + * API. + */ @Root(name = "AssumeRoleWithWebIdentityResponse", strict = false) @Namespace(reference = "https://sts.amazonaws.com/doc/2011-06-15/") - public static class WebIdentityResponse implements AssumeRoleBaseProvider.Response { + public static class Response implements BaseIdentityProvider.Response { @Path(value = "AssumeRoleWithWebIdentityResult") @Element(name = "Credentials") private Credentials credentials; diff --git a/api/src/main/java/io/minio/errors/ErrorResponseException.java b/api/src/main/java/io/minio/errors/ErrorResponseException.java index d2755932d..6f314cf1a 100644 --- a/api/src/main/java/io/minio/errors/ErrorResponseException.java +++ b/api/src/main/java/io/minio/errors/ErrorResponseException.java @@ -16,9 +16,7 @@ package io.minio.errors; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.minio.messages.ErrorResponse; -import okhttp3.Request; import okhttp3.Response; /** Thrown to indicate that error response is received when executing Amazon S3 operation. */ @@ -28,8 +26,8 @@ public class ErrorResponseException extends MinioException { private final ErrorResponse errorResponse; - @SuppressFBWarnings( - value = "Se", + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SE_BAD_FIELD", justification = "There's really no excuse except that nobody has complained") private final Response response; @@ -40,7 +38,7 @@ public ErrorResponseException(ErrorResponse errorResponse, Response response, St this.response = response; } - /** Returns ErrorResponse contains detail of what error occured. */ + /** Returns ErrorResponse contains detail of what error occurred. */ public ErrorResponse errorResponse() { return this.errorResponse; } @@ -51,30 +49,19 @@ public Response response() { @Override public String toString() { - Request request = response.request(); - return "error occurred\n" - + errorResponse.toString() - + "\n" - + "request={" - + "method=" - + request.method() - + ", " - + "url=" - + request.url() - + ", " - + "headers=" - + request + return String.format( + "S3 operation failed; ErrorResponseException{errorResponse=%s, request={method=%s, url=%s," + + " headers=%s}, response={code=%s, headers=%s}}", + errorResponse.toString(), + response.request().method(), + response.request().url(), + response + .request() .headers() .toString() .replaceAll("Signature=([0-9a-f]+)", "Signature=*REDACTED*") - .replaceAll("Credential=([^/]+)", "Credential=*REDACTED*") - + "}\n" - + "response={" - + "code=" - + response.code() - + ", " - + "headers=" - + response.headers() - + "}\n"; + .replaceAll("Credential=([^/]+)", "Credential=*REDACTED*"), + response.code(), + response.headers().toString()); } } diff --git a/api/src/main/java/io/minio/errors/InternalException.java b/api/src/main/java/io/minio/errors/InternalException.java index 4ba3e4746..5e0c1450b 100644 --- a/api/src/main/java/io/minio/errors/InternalException.java +++ b/api/src/main/java/io/minio/errors/InternalException.java @@ -17,11 +17,17 @@ package io.minio.errors; /** - * Thrown to indicate that unexpected internal library error occured while processing given request. + * Thrown to indicate that unexpected internal library error occurred while processing given + * request. */ public class InternalException extends MinioException { private static final long serialVersionUID = 138336287983212416L; + /** Constructs a new InternalException with given error message. */ + public InternalException(String message) { + super(message); + } + /** Constructs a new InternalException with given error message. */ public InternalException(String message, String httpTrace) { super(message, httpTrace); diff --git a/api/src/main/java/io/minio/errors/MinioException.java b/api/src/main/java/io/minio/errors/MinioException.java index 108db2805..af5f7de13 100644 --- a/api/src/main/java/io/minio/errors/MinioException.java +++ b/api/src/main/java/io/minio/errors/MinioException.java @@ -16,17 +16,22 @@ package io.minio.errors; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import java.io.EOFException; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + /** Base Exception class for all minio-java exceptions. */ public class MinioException extends Exception { private static final long serialVersionUID = -7241010318779326306L; String httpTrace = null; - /** Constructs a new MinioException. */ - public MinioException() { - super(); - } - /** Constructs a new MinioException with given error message. */ public MinioException(String message) { super(message); @@ -38,7 +43,52 @@ public MinioException(String message, String httpTrace) { this.httpTrace = httpTrace; } + /** Constructs a new MinioException with the specified detail message and cause. */ + public MinioException(String message, Throwable cause) { + super(message, cause); + } + + /** Constructs a new MinioException with the specified cause. */ + public MinioException(Throwable cause) { + super(cause); + } + public String httpTrace() { return this.httpTrace; } + + /** Throws encapsulated exception. */ + public void throwEncapsulatedException() + throws BucketPolicyTooLargeException, EOFException, ErrorResponseException, + GeneralSecurityException, InsufficientDataException, InternalException, + InterruptedException, InvalidKeyException, InvalidResponseException, IOException, + JsonMappingException, JsonParseException, JsonProcessingException, KeyManagementException, + MinioException, NoSuchAlgorithmException, ServerException, XmlParserException { + Throwable e = getCause(); + + // Inherited by MinioException + if (e instanceof BucketPolicyTooLargeException) throw (BucketPolicyTooLargeException) e; + if (e instanceof ErrorResponseException) throw (ErrorResponseException) e; + if (e instanceof InsufficientDataException) throw (InsufficientDataException) e; + if (e instanceof InternalException) throw (InternalException) e; + if (e instanceof InvalidResponseException) throw (InvalidResponseException) e; + if (e instanceof ServerException) throw (ServerException) e; + if (e instanceof XmlParserException) throw (XmlParserException) e; + + // Inherited by IOException + if (e instanceof JsonMappingException) throw (JsonMappingException) e; + if (e instanceof JsonParseException) throw (JsonParseException) e; + if (e instanceof JsonProcessingException) throw (JsonProcessingException) e; + if (e instanceof EOFException) throw (EOFException) e; + if (e instanceof IOException) throw (IOException) e; + + // Inherited by GeneralSecurityException + if (e instanceof InvalidKeyException) throw (InvalidKeyException) e; + if (e instanceof KeyManagementException) throw (KeyManagementException) e; + if (e instanceof NoSuchAlgorithmException) throw (NoSuchAlgorithmException) e; + if (e instanceof GeneralSecurityException) throw (GeneralSecurityException) e; + + if (e instanceof InterruptedException) throw (InterruptedException) e; + throw this; + } } diff --git a/api/src/main/java/io/minio/errors/XmlParserException.java b/api/src/main/java/io/minio/errors/XmlParserException.java index 55de48554..5b2627596 100644 --- a/api/src/main/java/io/minio/errors/XmlParserException.java +++ b/api/src/main/java/io/minio/errors/XmlParserException.java @@ -21,6 +21,6 @@ public class XmlParserException extends MinioException { private static final long serialVersionUID = -3877568719271880309L; public XmlParserException(Exception e) { - super(e.toString()); + super(e); } } diff --git a/api/src/main/java/io/minio/http/HttpUtils.java b/api/src/main/java/io/minio/http/HttpUtils.java deleted file mode 100644 index b69f3d2c2..000000000 --- a/api/src/main/java/io/minio/http/HttpUtils.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.http; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.minio.org.apache.commons.validator.routines.InetAddressValidator; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Protocol; - -/** HTTP utilities. */ -public class HttpUtils { - public static final String AWS_S3_PREFIX = - "^(((bucket\\.|accesspoint\\.)" - + "vpce(-(?!_)[a-z_\\d]+(? 80, HTTPS -> 443 - if ((url.scheme().equals("http") && url.port() == 80) - || (url.scheme().equals("https") && url.port() == 443)) { - return host; - } - - return host + ":" + url.port(); - } - - private static OkHttpClient enableJKSPKCS12Certificates( - OkHttpClient httpClient, - String trustStorePath, - String trustStorePassword, - String keyStorePath, - String keyStorePassword, - String keyStoreType) - throws GeneralSecurityException, IOException { - if (trustStorePath == null || trustStorePath.isEmpty()) { - throw new IllegalArgumentException("trust store path must be provided"); - } - if (trustStorePassword == null) { - throw new IllegalArgumentException("trust store password must be provided"); - } - if (keyStorePath == null || keyStorePath.isEmpty()) { - throw new IllegalArgumentException("key store path must be provided"); - } - if (keyStorePassword == null) { - throw new IllegalArgumentException("key store password must be provided"); - } - - SSLContext sslContext = SSLContext.getInstance("TLS"); - KeyStore trustStore = KeyStore.getInstance("JKS"); - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - try (FileInputStream trustInput = new FileInputStream(trustStorePath); - FileInputStream keyInput = new FileInputStream(keyStorePath); ) { - trustStore.load(trustInput, trustStorePassword.toCharArray()); - keyStore.load(keyInput, keyStorePassword.toCharArray()); - } - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(trustStore); - - KeyManagerFactory keyManagerFactory = - KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, keyStorePassword.toCharArray()); - - sslContext.init( - keyManagerFactory.getKeyManagers(), - trustManagerFactory.getTrustManagers(), - new java.security.SecureRandom()); - - return httpClient - .newBuilder() - .sslSocketFactory( - sslContext.getSocketFactory(), - (X509TrustManager) trustManagerFactory.getTrustManagers()[0]) - .build(); - } - - public static OkHttpClient enableJKSCertificates( - OkHttpClient httpClient, - String trustStorePath, - String trustStorePassword, - String keyStorePath, - String keyStorePassword) - throws GeneralSecurityException, IOException { - return enableJKSPKCS12Certificates( - httpClient, trustStorePath, trustStorePassword, keyStorePath, keyStorePassword, "JKS"); - } - - public static OkHttpClient enablePKCS12Certificates( - OkHttpClient httpClient, - String trustStorePath, - String trustStorePassword, - String keyStorePath, - String keyStorePassword) - throws GeneralSecurityException, IOException { - return enableJKSPKCS12Certificates( - httpClient, trustStorePath, trustStorePassword, keyStorePath, keyStorePassword, "PKCS12"); - } - - /** - * copied logic from - * https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java - */ - public static OkHttpClient enableExternalCertificates(OkHttpClient httpClient, String filename) - throws GeneralSecurityException, IOException { - Collection certificates = null; - try (FileInputStream fis = new FileInputStream(filename)) { - certificates = CertificateFactory.getInstance("X.509").generateCertificates(fis); - } - - if (certificates == null || certificates.isEmpty()) { - throw new IllegalArgumentException("expected non-empty set of trusted certificates"); - } - - char[] password = "password".toCharArray(); // Any password will work. - - // Put the certificates a key store. - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - // By convention, 'null' creates an empty key store. - keyStore.load(null, password); - - int index = 0; - for (Certificate certificate : certificates) { - String certificateAlias = Integer.toString(index++); - keyStore.setCertificateEntry(certificateAlias, certificate); - } - - // Use it to build an X509 trust manager. - KeyManagerFactory keyManagerFactory = - KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, password); - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(keyStore); - - final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); - final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagers, trustManagers, null); - SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); - - return httpClient - .newBuilder() - .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0]) - .build(); - } - - public static OkHttpClient newDefaultHttpClient( - long connectTimeout, long writeTimeout, long readTimeout) { - OkHttpClient httpClient = - new OkHttpClient() - .newBuilder() - .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS) - .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS) - .readTimeout(readTimeout, TimeUnit.MILLISECONDS) - .protocols(Arrays.asList(Protocol.HTTP_1_1)) - .build(); - String filename = System.getenv("SSL_CERT_FILE"); - if (filename != null && !filename.isEmpty()) { - try { - httpClient = enableExternalCertificates(httpClient, filename); - } catch (GeneralSecurityException | IOException e) { - throw new RuntimeException(e); - } - } - return httpClient; - } - - @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.") - public static OkHttpClient disableCertCheck(OkHttpClient client) - throws KeyManagementException, NoSuchAlgorithmException { - final TrustManager[] trustAllCerts = - new TrustManager[] { - new X509TrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException {} - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException {} - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[] {}; - } - } - }; - - final SSLContext sslContext = SSLContext.getInstance("SSL"); - sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); - final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); - - return client - .newBuilder() - .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]) - .hostnameVerifier( - new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }) - .build(); - } - - public static OkHttpClient setTimeout( - OkHttpClient client, long connectTimeout, long writeTimeout, long readTimeout) { - return client - .newBuilder() - .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS) - .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS) - .readTimeout(readTimeout, TimeUnit.MILLISECONDS) - .build(); - } -} diff --git a/api/src/main/java/io/minio/http/Method.java b/api/src/main/java/io/minio/http/Method.java deleted file mode 100644 index e5224f813..000000000 --- a/api/src/main/java/io/minio/http/Method.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio.http; - -/** HTTP methods. */ -public enum Method { - GET, - HEAD, - POST, - PUT, - DELETE; -} diff --git a/api/src/main/java/io/minio/messages/AbortIncompleteMultipartUpload.java b/api/src/main/java/io/minio/messages/AbortIncompleteMultipartUpload.java deleted file mode 100644 index 8704396c2..000000000 --- a/api/src/main/java/io/minio/messages/AbortIncompleteMultipartUpload.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote abort incomplete multipart upload information for {@link LifecycleRule}. - */ -@Root(name = "AbortIncompleteMultipartUpload") -public class AbortIncompleteMultipartUpload { - @Element(name = "DaysAfterInitiation") - private int daysAfterInitiation; - - public AbortIncompleteMultipartUpload( - @Element(name = "DaysAfterInitiation") int daysAfterInitiation) { - this.daysAfterInitiation = daysAfterInitiation; - } - - public int daysAfterInitiation() { - return daysAfterInitiation; - } -} diff --git a/api/src/main/java/io/minio/messages/AccessControlList.java b/api/src/main/java/io/minio/messages/AccessControlList.java index fff7fc582..bfa92289c 100644 --- a/api/src/main/java/io/minio/messages/AccessControlList.java +++ b/api/src/main/java/io/minio/messages/AccessControlList.java @@ -20,10 +20,18 @@ import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.simpleframework.xml.Attribute; +import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; +import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; +import org.simpleframework.xml.convert.Converter; +import org.simpleframework.xml.stream.InputNode; +import org.simpleframework.xml.stream.OutputNode; -/** Helper class to denote access control list of {@link S3OutputLocation}. */ +/** Access control list of {@link RestoreRequest.S3} and {@link AccessControlPolicy}. */ @Root(name = "AccessControlList") @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public class AccessControlList { @@ -42,4 +50,186 @@ public AccessControlList( public List grants() { return Utils.unmodifiableList(grants); } + + @Override + public String toString() { + return String.format("AccessControlList{grants=%s}", Utils.stringify(grants)); + } + + /** Grant information of {@link AccessControlList}. */ + @Root(name = "Grant") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class Grant { + @Element(name = "Grantee", required = false) + private Grantee grantee; + + @Element(name = "Permission", required = false) + private Permission permission; + + public Grant( + @Nullable @Element(name = "Grantee", required = false) Grantee grantee, + @Nullable @Element(name = "Permission", required = false) Permission permission) { + if (grantee == null && permission == null) { + throw new IllegalArgumentException("Either Grantee or Permission must be provided"); + } + this.grantee = grantee; + this.permission = permission; + } + + public Grantee grantee() { + return grantee; + } + + public Permission permission() { + return permission; + } + + public String granteeUri() { + return grantee == null ? null : grantee.uri(); + } + + public String granteeId() { + return grantee == null ? null : grantee.id(); + } + + @Override + public String toString() { + return String.format( + "Grant{grantee=%s, permission=%s}", + Utils.stringify(grantee), Utils.stringify(permission)); + } + } + + /** Grantee information of {@link AccessControlList}. */ + @Root(name = "Grantee") + @Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class Grantee { + @Attribute(name = "type") + private String xsiType; + + @Element(name = "DisplayName", required = false) + private String displayName; + + @Element(name = "EmailAddress", required = false) + private String emailAddress; + + @Element(name = "ID", required = false) + private String id; + + @Element(name = "Type") + private Type type; + + @Element(name = "URI", required = false) + private String uri; + + public Grantee( + @Nonnull Type type, + @Nullable String displayName, + @Nullable String emailAddress, + @Nullable String id, + @Nullable String uri) { + this.type = Objects.requireNonNull(type, "Type must not be null"); + this.displayName = displayName; + this.emailAddress = emailAddress; + this.id = id; + this.uri = uri; + } + + public Grantee( + @Nonnull @Attribute(name = "type") String xsiType, + @Nonnull @Element(name = "Type") Type type, + @Nullable @Element(name = "DisplayName", required = false) String displayName, + @Nullable @Element(name = "EmailAddress", required = false) String emailAddress, + @Nullable @Element(name = "ID", required = false) String id, + @Nullable @Element(name = "URI", required = false) String uri) { + this(type, displayName, emailAddress, id, uri); + this.xsiType = xsiType; + } + + public String displayName() { + return displayName; + } + + public String emailAddress() { + return emailAddress; + } + + public String id() { + return id; + } + + public Type type() { + return type; + } + + public String uri() { + return uri; + } + + @Override + public String toString() { + return String.format( + "Grantee{xsiType=%s, displayName=%s, emailAddress=%s, id=%s, type=%s, uri=%s}", + xsiType, + Utils.stringify(displayName), + Utils.stringify(emailAddress), + Utils.stringify(id), + Utils.stringify(type), + Utils.stringify(uri)); + } + } + + /** Grantee type of {@link AccessControlList.Grantee}. */ + @Root(name = "Type") + @Convert(Type.TypeConverter.class) + public static enum Type { + CANONICAL_USER("CanonicalUser"), + AMAZON_CUSTOMER_BY_EMAIL("AmazonCustomerByEmail"), + GROUP("Group"); + + private final String value; + + private Type(String value) { + this.value = value; + } + + public String toString() { + return this.value; + } + + /** Returns Type of given string. */ + public static Type fromString(String granteeTypeString) { + for (Type granteeType : Type.values()) { + if (granteeTypeString.equals(granteeType.value)) { + return granteeType; + } + } + + throw new IllegalArgumentException("Unknown grantee type '" + granteeTypeString + "'"); + } + + /** XML converter of Grantee {@link AccessControlList.Type}. */ + public static class TypeConverter implements Converter { + @Override + public Type read(InputNode node) throws Exception { + return Type.fromString(node.getValue()); + } + + @Override + public void write(OutputNode node, Type granteeType) throws Exception { + node.setValue(granteeType.toString()); + } + } + } + + /** Grant permission of {@link AccessControlList.Grant}. */ + @Root(name = "Permission") + public static enum Permission { + FULL_CONTROL, + WRITE, + WRITE_ACP, + READ, + READ_ACP; + } } diff --git a/api/src/main/java/io/minio/messages/AccessControlPolicy.java b/api/src/main/java/io/minio/messages/AccessControlPolicy.java index f9b95921e..409a803c7 100644 --- a/api/src/main/java/io/minio/messages/AccessControlPolicy.java +++ b/api/src/main/java/io/minio/messages/AccessControlPolicy.java @@ -18,12 +18,13 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import io.minio.Utils; import java.util.List; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; /** - * Object representation of response XML of GetObjectAcl * API. */ @@ -54,18 +55,20 @@ public AccessControlList accessControlList() { public String cannedAcl() { if (accessControlList == null) return ""; - List grants = accessControlList.grants(); + List grants = accessControlList.grants(); int size = grants.size(); if (size < 1 || size > 3) return ""; - for (Grant grant : grants) { + for (AccessControlList.Grant grant : grants) { if (grant == null) continue; String uri = grant.granteeUri(); - if (grant.permission() == Permission.FULL_CONTROL && size == 1 && "".equals(uri)) { + if (grant.permission() == AccessControlList.Permission.FULL_CONTROL + && size == 1 + && "".equals(uri)) { return "private"; - } else if (grant.permission() == Permission.READ && size == 2) { + } else if (grant.permission() == AccessControlList.Permission.READ && size == 2) { if ("http://acs.amazonaws.com/groups/global/AuthenticatedUsers".equals(uri)) { return "authenticated-read"; } @@ -75,7 +78,7 @@ public String cannedAcl() { && owner.id().equals(grant.granteeId())) { return "bucket-owner-read"; } - } else if (grant.permission() == Permission.WRITE + } else if (grant.permission() == AccessControlList.Permission.WRITE && size == 3 && "http://acs.amazonaws.com/groups/global/AllUsers".equals(uri)) { return "public-read-write"; @@ -90,19 +93,19 @@ public Multimap grantAcl() { if (accessControlList != null) { map = HashMultimap.create(); - for (Grant grant : accessControlList.grants()) { + for (AccessControlList.Grant grant : accessControlList.grants()) { if (grant == null) continue; String value = "id=" + grant.granteeId(); - if (grant.permission() == Permission.READ) { + if (grant.permission() == AccessControlList.Permission.READ) { map.put("X-Amz-Grant-Read", value); - } else if (grant.permission() == Permission.WRITE) { + } else if (grant.permission() == AccessControlList.Permission.WRITE) { map.put("X-Amz-Grant-Write", value); - } else if (grant.permission() == Permission.READ_ACP) { + } else if (grant.permission() == AccessControlList.Permission.READ_ACP) { map.put("X-Amz-Grant-Read-Acp", value); - } else if (grant.permission() == Permission.WRITE_ACP) { + } else if (grant.permission() == AccessControlList.Permission.WRITE_ACP) { map.put("X-Amz-Grant-Write-Acp", value); - } else if (grant.permission() == Permission.FULL_CONTROL) { + } else if (grant.permission() == AccessControlList.Permission.FULL_CONTROL) { map.put("X-Amz-Grant-Full-Control", value); } } @@ -110,4 +113,11 @@ public Multimap grantAcl() { return map; } + + @Override + public String toString() { + return String.format( + "AccessControlPolicy(owner=%s, accessControlList=%s)", + Utils.stringify(owner), Utils.stringify(accessControlList)); + } } diff --git a/api/src/main/java/io/minio/messages/AccessControlTranslation.java b/api/src/main/java/io/minio/messages/AccessControlTranslation.java deleted file mode 100644 index 0461e05f0..000000000 --- a/api/src/main/java/io/minio/messages/AccessControlTranslation.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote access control translation information for {@link ReplicationDestination}. - */ -@Root(name = "AccessControlTranslation") -public class AccessControlTranslation { - @Element(name = "Owner") - private String owner = "Destination"; - - public AccessControlTranslation(@Nonnull @Element(name = "Owner") String owner) { - this.owner = Objects.requireNonNull(owner, "Owner must not be null"); - } - - public String owner() { - return this.owner; - } -} diff --git a/api/src/main/java/io/minio/messages/AndOperator.java b/api/src/main/java/io/minio/messages/AndOperator.java deleted file mode 100644 index 0e6774e2e..000000000 --- a/api/src/main/java/io/minio/messages/AndOperator.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import io.minio.Utils; -import java.util.Map; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.ElementMap; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; - -/** Helper class to denote AND operator information for {@link RuleFilter}. */ -@Root(name = "And") -public class AndOperator { - @Element(name = "Prefix", required = false) - @Convert(PrefixConverter.class) - private String prefix; - - @Element(name = "ObjectSizeLessThan", required = false) - private Long objectSizeLessThan; - - @Element(name = "ObjectSizeGreaterThan", required = false) - private Long objectSizeGreaterThan; - - @ElementMap( - attribute = false, - entry = "Tag", - inline = true, - key = "Key", - value = "Value", - required = false) - private Map tags; - - public AndOperator( - @Nullable @Element(name = "Prefix", required = false) String prefix, - @Nullable - @ElementMap( - attribute = false, - entry = "Tag", - inline = true, - key = "Key", - value = "Value", - required = false) - Map tags) { - if (prefix == null && tags == null) { - throw new IllegalArgumentException("At least Prefix or Tags must be set"); - } - - if (tags != null) { - for (String key : tags.keySet()) { - if (key.isEmpty()) { - throw new IllegalArgumentException("Tags must not contain empty key"); - } - } - } - - this.prefix = prefix; - this.tags = Utils.unmodifiableMap(tags); - } - - public AndOperator( - @Nullable @Element(name = "Prefix", required = false) String prefix, - @Nullable - @ElementMap( - attribute = false, - entry = "Tag", - inline = true, - key = "Key", - value = "Value", - required = false) - Map tags, - @Nullable @Element(name = "ObjectSizeLessThan", required = false) Long objectSizeLessThan, - @Nullable @Element(name = "ObjectSizeGreaterThan", required = false) - Long objectSizeGreaterThan) { - this(prefix, tags); - this.objectSizeLessThan = objectSizeLessThan; - this.objectSizeGreaterThan = objectSizeGreaterThan; - } - - public String prefix() { - return this.prefix; - } - - public Long objectSizeLessThan() { - return this.objectSizeLessThan; - } - - public Long objectSizeGreaterThan() { - return this.objectSizeGreaterThan; - } - - public Map tags() { - return this.tags; - } -} diff --git a/api/src/main/java/io/minio/messages/BasePartsResult.java b/api/src/main/java/io/minio/messages/BasePartsResult.java new file mode 100644 index 000000000..183260271 --- /dev/null +++ b/api/src/main/java/io/minio/messages/BasePartsResult.java @@ -0,0 +1,78 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, 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 io.minio.messages; + +import io.minio.Utils; +import java.util.List; +import org.simpleframework.xml.Element; +import org.simpleframework.xml.ElementList; +import org.simpleframework.xml.Root; + +/** + * Base part information for {@link ListPartsResult} and {@link + * GetObjectAttributesOutput.ObjectParts}. + */ +@Root(name = "BasePartsResult", strict = false) +public abstract class BasePartsResult { + @Element(name = "IsTruncated", required = false) + private boolean isTruncated; + + @Element(name = "MaxParts", required = false) + private Integer maxParts; + + @Element(name = "NextPartNumberMarker", required = false) + private Integer nextPartNumberMarker; + + @Element(name = "PartNumberMarker", required = false) + private Integer partNumberMarker; + + @ElementList(name = "Part", inline = true, required = false) + private List parts; + + public BasePartsResult() {} + + public boolean isTruncated() { + return isTruncated; + } + + public Integer maxParts() { + return maxParts; + } + + public Integer nextPartNumberMarker() { + return nextPartNumberMarker; + } + + public Integer partNumberMarker() { + return partNumberMarker; + } + + public List parts() { + return Utils.unmodifiableList(parts); + } + + @Override + public String toString() { + return String.format( + "isTruncated=%s, maxParts=%s, nextPartNumberMarker=%s, partNumberMarker=%s, parts=%s", + Utils.stringify(isTruncated), + Utils.stringify(maxParts), + Utils.stringify(nextPartNumberMarker), + Utils.stringify(partNumberMarker), + Utils.stringify(parts)); + } +} diff --git a/api/src/main/java/io/minio/messages/SelectObjectContentRequestBase.java b/api/src/main/java/io/minio/messages/BaseSelectParameters.java similarity index 88% rename from api/src/main/java/io/minio/messages/SelectObjectContentRequestBase.java rename to api/src/main/java/io/minio/messages/BaseSelectParameters.java index 3bce8fc8b..8bdf67a2a 100644 --- a/api/src/main/java/io/minio/messages/SelectObjectContentRequestBase.java +++ b/api/src/main/java/io/minio/messages/BaseSelectParameters.java @@ -20,9 +20,12 @@ import javax.annotation.Nonnull; import org.simpleframework.xml.Element; -/** Base class for {@link SelectObjectContentRequest} and {@link SelectParameters}. */ +/** + * Base select parameters information for {@link SelectObjectContentRequest} and {@link + * RestoreRequest.SelectParameters}. + */ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public abstract class SelectObjectContentRequestBase { +public abstract class BaseSelectParameters { @Element(name = "Expression") private String expression; @@ -35,7 +38,7 @@ public abstract class SelectObjectContentRequestBase { @Element(name = "OutputSerialization") private OutputSerialization outputSerialization; - public SelectObjectContentRequestBase( + public BaseSelectParameters( @Nonnull String expression, @Nonnull InputSerialization is, @Nonnull OutputSerialization os) { this.expression = Objects.requireNonNull(expression, "Expression must not be null"); this.inputSerialization = Objects.requireNonNull(is, "InputSerialization must not be null"); diff --git a/api/src/main/java/io/minio/messages/Bucket.java b/api/src/main/java/io/minio/messages/Bucket.java deleted file mode 100644 index bd4d150ec..000000000 --- a/api/src/main/java/io/minio/messages/Bucket.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio.messages; - -import java.time.ZonedDateTime; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote bucket information for {@link ListAllMyBucketsResult}. */ -@Root(name = "Bucket", strict = false) -public class Bucket { - @Element(name = "Name") - private String name; - - @Element(name = "CreationDate") - private ResponseDate creationDate; - - @Element(name = "BucketRegion", required = false) - private String bucketRegion; - - public Bucket() {} - - /** Returns bucket name. */ - public String name() { - return name; - } - - /** Returns creation date. */ - public ZonedDateTime creationDate() { - return creationDate.zonedDateTime(); - } - - public String bucketRegion() { - return bucketRegion; - } -} diff --git a/api/src/main/java/io/minio/messages/BucketMetadata.java b/api/src/main/java/io/minio/messages/BucketMetadata.java deleted file mode 100644 index 91be4e8de..000000000 --- a/api/src/main/java/io/minio/messages/BucketMetadata.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2020 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** Helper class to denote bucket information for {@link EventMetadata}. */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = "UwF", - justification = "Everything in this class is initialized by JSON unmarshalling.") -public class BucketMetadata { - @JsonProperty private String name; - @JsonProperty private Identity ownerIdentity; - @JsonProperty private String arn; - - public String name() { - return name; - } - - public String owner() { - if (ownerIdentity == null) { - return null; - } - - return ownerIdentity.principalId(); - } - - public String arn() { - return arn; - } -} diff --git a/api/src/main/java/io/minio/messages/CORSConfiguration.java b/api/src/main/java/io/minio/messages/CORSConfiguration.java index aedc3d253..c2b0f13dd 100644 --- a/api/src/main/java/io/minio/messages/CORSConfiguration.java +++ b/api/src/main/java/io/minio/messages/CORSConfiguration.java @@ -25,7 +25,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of request/response XML of PutBucketCors * API and GetBucketCors @@ -46,6 +46,12 @@ public List rules() { return Utils.unmodifiableList(rules); } + @Override + public String toString() { + return String.format("CORSConfiguration{rules=%s}", Utils.stringify(rules)); + } + + /** CORS rule of {@link CORSConfiguration}. */ public static class CORSRule { @ElementList(entry = "AllowedHeader", inline = true, required = false) private List allowedHeaders; @@ -107,5 +113,18 @@ public String id() { public Integer maxAgeSeconds() { return maxAgeSeconds; } + + @Override + public String toString() { + return String.format( + "CORSRule{allowedHeaders=%s, allowedMethods=%s, allowedOrigins=%s, exposeHeaders=%s, " + + "id=%s, maxAgeSeconds=%s}", + Utils.stringify(allowedHeaders), + Utils.stringify(allowedMethods), + Utils.stringify(allowedOrigins), + Utils.stringify(exposeHeaders), + Utils.stringify(id), + Utils.stringify(maxAgeSeconds)); + } } } diff --git a/api/src/main/java/io/minio/messages/CannedAcl.java b/api/src/main/java/io/minio/messages/CannedAcl.java deleted file mode 100644 index dc067d34a..000000000 --- a/api/src/main/java/io/minio/messages/CannedAcl.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonCreator; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; -import org.simpleframework.xml.convert.Converter; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.OutputNode; - -/** CannedAcl representing retrieval cannedAcl value. */ -@Root(name = "CannedAcl") -@Convert(CannedAcl.CannedAclConverter.class) -public enum CannedAcl { - PRIVATE("private"), - PUBLIC_READ("public-read"), - PUBLIC_READ_WRITE("public-read-write"), - AUTHENTICATED_READ("authenticated-read"), - AWS_EXEC_READ("aws-exec-read"), - BUCKET_OWNER_READ("bucket-owner-read"), - BUCKET_OWNER_FULL_CONTROL("bucket-owner-full-control"); - - private final String value; - - private CannedAcl(String value) { - this.value = value; - } - - public String toString() { - return this.value; - } - - /** Returns CannedAcl of given string. */ - @JsonCreator - public static CannedAcl fromString(String cannedAclString) { - for (CannedAcl cannedAcl : CannedAcl.values()) { - if (cannedAclString.equals(cannedAcl.value)) { - return cannedAcl; - } - } - - throw new IllegalArgumentException("Unknown canned ACL '" + cannedAclString + "'"); - } - - /** XML converter class. */ - public static class CannedAclConverter implements Converter { - @Override - public CannedAcl read(InputNode node) throws Exception { - return CannedAcl.fromString(node.getValue()); - } - - @Override - public void write(OutputNode node, CannedAcl cannedAcl) throws Exception { - node.setValue(cannedAcl.toString()); - } - } -} diff --git a/api/src/main/java/io/minio/messages/Checksum.java b/api/src/main/java/io/minio/messages/Checksum.java index 2263fa138..2c965ad2c 100644 --- a/api/src/main/java/io/minio/messages/Checksum.java +++ b/api/src/main/java/io/minio/messages/Checksum.java @@ -16,13 +16,12 @@ package io.minio.messages; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import java.util.Locale; +import io.minio.Http; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; -/** Helper class for. */ +/** Object checksum information. */ @Root(name = "Checksum", strict = false) public class Checksum { @Element(name = "ChecksumCRC32", required = false) @@ -45,6 +44,30 @@ public class Checksum { public Checksum() {} + public Checksum(Checksum checksum) { + this.checksumCRC32 = checksum.checksumCRC32; + this.checksumCRC32C = checksum.checksumCRC32C; + this.checksumCRC64NVME = checksum.checksumCRC64NVME; + this.checksumSHA1 = checksum.checksumSHA1; + this.checksumSHA256 = checksum.checksumSHA256; + this.checksumType = checksum.checksumType; + } + + public Checksum( + String checksumCRC32, + String checksumCRC32C, + String checksumCRC64NVME, + String checksumSHA1, + String checksumSHA256, + String checksumType) { + this.checksumCRC32 = checksumCRC32; + this.checksumCRC32C = checksumCRC32C; + this.checksumCRC64NVME = checksumCRC64NVME; + this.checksumSHA1 = checksumSHA1; + this.checksumSHA256 = checksumSHA256; + this.checksumType = checksumType; + } + public String checksumCRC32() { return checksumCRC32; } @@ -69,20 +92,36 @@ public String checksumType() { return checksumType; } - private void addHeader(Multimap map, String algorithm, String value) { - if (value != null || !value.isEmpty()) { - map.put("x-amz-checksum-algorithm", algorithm); - map.put("x-amz-checksum-algorithm-" + algorithm.toLowerCase(Locale.US), value); - } + private void addHeader(Http.Headers headers, String algorithm, String value) { + if (value == null || value.isEmpty()) return; + headers.put("x-amz-checksum-algorithm-" + algorithm, value); + headers.put("x-amz-checksum-algorithm", algorithm); + } + + public Http.Headers headers() { + Http.Headers headers = new Http.Headers(); + addHeader(headers, "crc32", checksumCRC32); + addHeader(headers, "crc32c", checksumCRC32C); + addHeader(headers, "crc64nvme", checksumCRC64NVME); + addHeader(headers, "sha1", checksumSHA1); + addHeader(headers, "sha256", checksumSHA256); + return headers; + } + + protected String stringify() { + return String.format( + "checksumCRC32=%s, checksumCRC32C=%s, checksumCRC64NVME=%s, checksumSHA1=%s," + + " checksumSHA256=%s, checksumType=%s", + Utils.stringify(checksumCRC32), + Utils.stringify(checksumCRC32C), + Utils.stringify(checksumCRC64NVME), + Utils.stringify(checksumSHA1), + Utils.stringify(checksumSHA256), + Utils.stringify(checksumType)); } - public Multimap headers() { - Multimap map = HashMultimap.create(); - addHeader(map, "CRC32", checksumCRC32); - addHeader(map, "CRC32C", checksumCRC32C); - addHeader(map, "CRC64NVME", checksumCRC64NVME); - addHeader(map, "SHA1", checksumSHA1); - addHeader(map, "SHA256", checksumSHA256); - return map; + @Override + public String toString() { + return String.format("Checksum{%s}", stringify()); } } diff --git a/api/src/main/java/io/minio/messages/CloudFunctionConfiguration.java b/api/src/main/java/io/minio/messages/CloudFunctionConfiguration.java deleted file mode 100644 index 013a28a2b..000000000 --- a/api/src/main/java/io/minio/messages/CloudFunctionConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote CloudFunction configuration of {@link NotificationConfiguration}. */ -@Root(name = "CloudFunctionConfiguration", strict = false) -public class CloudFunctionConfiguration extends NotificationCommonConfiguration { - @Element(name = "CloudFunction") - private String cloudFunction; - - public CloudFunctionConfiguration() { - super(); - } - - /** Returns cloudFunction. */ - public String cloudFunction() { - return cloudFunction; - } - - /** Sets cloudFunction. */ - public void setCloudFunction(String cloudFunction) { - this.cloudFunction = cloudFunction; - } -} diff --git a/api/src/main/java/io/minio/messages/CompleteMultipartUpload.java b/api/src/main/java/io/minio/messages/CompleteMultipartUpload.java index 94a9b91dc..36106e14f 100644 --- a/api/src/main/java/io/minio/messages/CompleteMultipartUpload.java +++ b/api/src/main/java/io/minio/messages/CompleteMultipartUpload.java @@ -26,7 +26,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of request XML of CompleteMultipartUpload * API. */ @@ -35,13 +35,13 @@ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public class CompleteMultipartUpload { @ElementList(name = "Part", inline = true) - private List partList; + private List parts; - /** Constucts a new CompleteMultipartUpload object with given parts. */ + /** Constructs a new CompleteMultipartUpload object with given parts. */ public CompleteMultipartUpload(@Nonnull Part[] parts) throws IllegalArgumentException { if (Objects.requireNonNull(parts, "parts must not be null").length == 0) { throw new IllegalArgumentException("parts cannot be empty"); } - this.partList = Utils.unmodifiableList(Arrays.asList(parts)); + this.parts = Utils.unmodifiableList(Arrays.asList(parts)); } } diff --git a/api/src/main/java/io/minio/messages/CompleteMultipartUploadOutput.java b/api/src/main/java/io/minio/messages/CompleteMultipartUploadOutput.java deleted file mode 100644 index 78d504a79..000000000 --- a/api/src/main/java/io/minio/messages/CompleteMultipartUploadOutput.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Namespace; -import org.simpleframework.xml.Root; - -/** - * Object representation of response XML of CompleteMultipartUpload - * API. - */ -@Root(name = "CompleteMultipartUploadOutput") -@Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class CompleteMultipartUploadOutput extends CompleteMultipartUploadResult {} diff --git a/api/src/main/java/io/minio/messages/CompleteMultipartUploadResult.java b/api/src/main/java/io/minio/messages/CompleteMultipartUploadResult.java index fed1a0901..e5443d326 100644 --- a/api/src/main/java/io/minio/messages/CompleteMultipartUploadResult.java +++ b/api/src/main/java/io/minio/messages/CompleteMultipartUploadResult.java @@ -16,18 +16,19 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of response XML of CompleteMultipartUpload * API. */ @Root(name = "CompleteMultipartUploadResult") @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class CompleteMultipartUploadResult { +public class CompleteMultipartUploadResult extends Checksum { @Element(name = "Location") private String location; @@ -40,24 +41,6 @@ public class CompleteMultipartUploadResult { @Element(name = "ETag") private String etag; - @Element(name = "ChecksumCRC32", required = false) - private String checksumCRC32; - - @Element(name = "ChecksumCRC32C", required = false) - private String checksumCRC32C; - - @Element(name = "ChecksumCRC64NVME", required = false) - private String checksumCRC64NVME; - - @Element(name = "ChecksumSHA1", required = false) - private String checksumSHA1; - - @Element(name = "ChecksumSHA256", required = false) - private String checksumSHA256; - - @Element(name = "ChecksumType", required = false) - private String checksumType; - public CompleteMultipartUploadResult() {} public String location() { @@ -76,27 +59,14 @@ public String etag() { return etag; } - public String checksumCRC32() { - return checksumCRC32; - } - - public String checksumCRC32C() { - return checksumCRC32C; - } - - public String checksumCRC64NVME() { - return checksumCRC64NVME; - } - - public String checksumSHA1() { - return checksumSHA1; - } - - public String checksumSHA256() { - return checksumSHA256; - } - - public String checksumType() { - return checksumType; + @Override + public String toString() { + return String.format( + "CompleteMultipartUploadResult{location=%s, bucket=%s, object=%s, etag=%s, %s}", + Utils.stringify(location), + Utils.stringify(bucket), + Utils.stringify(object), + Utils.stringify(etag), + super.stringify()); } } diff --git a/api/src/main/java/io/minio/messages/CompressionType.java b/api/src/main/java/io/minio/messages/CompressionType.java deleted file mode 100644 index 7b6424cfc..000000000 --- a/api/src/main/java/io/minio/messages/CompressionType.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -/** CSV/JSON object's compression format for select object content. */ -public enum CompressionType { - NONE, - GZIP, - BZIP2; -} diff --git a/api/src/main/java/io/minio/messages/Contents.java b/api/src/main/java/io/minio/messages/Contents.java index 873e800e7..eba2dad7f 100644 --- a/api/src/main/java/io/minio/messages/Contents.java +++ b/api/src/main/java/io/minio/messages/Contents.java @@ -18,10 +18,7 @@ import org.simpleframework.xml.Root; -/** - * Helper class to denote Object information in {@link ListBucketResultV1} and {@link - * ListBucketResultV2} - */ +/** Object information in {@link ListBucketResultV1} and {@link ListBucketResultV2} */ @Root(name = "Contents", strict = false) public class Contents extends Item { public Contents() { @@ -31,4 +28,9 @@ public Contents() { public Contents(String prefix) { super(prefix); } + + @Override + public String toString() { + return String.format("Contents{%s}", super.toString()); + } } diff --git a/api/src/main/java/io/minio/messages/CopyObjectResult.java b/api/src/main/java/io/minio/messages/CopyObjectResult.java index 628484b9a..75fe941d2 100644 --- a/api/src/main/java/io/minio/messages/CopyObjectResult.java +++ b/api/src/main/java/io/minio/messages/CopyObjectResult.java @@ -17,41 +17,25 @@ package io.minio.messages; +import io.minio.Time; +import io.minio.Utils; import java.time.ZonedDateTime; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of response XML of CopyObject API. */ @Root(name = "CopyObjectResult", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class CopyObjectResult { +public class CopyObjectResult extends Checksum { @Element(name = "ETag") private String etag; @Element(name = "LastModified") - private ResponseDate lastModified; - - @Element(name = "ChecksumType", required = false) - private String checksumType; - - @Element(name = "ChecksumCRC32", required = false) - private String checksumCRC32; - - @Element(name = "ChecksumCRC32C", required = false) - private String checksumCRC32C; - - @Element(name = "ChecksumCRC64NVME", required = false) - private String checksumCRC64NVME; - - @Element(name = "ChecksumSHA1", required = false) - private String checksumSHA1; - - @Element(name = "ChecksumSHA256", required = false) - private String checksumSHA256; + private Time.S3Time lastModified; public CopyObjectResult() {} @@ -62,30 +46,17 @@ public String etag() { /** Returns last modified time. */ public ZonedDateTime lastModified() { - return lastModified.zonedDateTime(); - } - - public String checksumType() { - return checksumType; - } - - public String checksumCRC32() { - return checksumCRC32; - } - - public String checksumCRC32C() { - return checksumCRC32C; - } - - public String checksumCRC64NVME() { - return checksumCRC64NVME; + return lastModified == null ? null : lastModified.toZonedDateTime(); } - public String checksumSHA1() { - return checksumSHA1; + protected String stringify() { + return String.format( + "etag=%s, lastModified=%s, %s", + Utils.stringify(etag), Utils.stringify(lastModified), super.stringify()); } - public String checksumSHA256() { - return checksumSHA256; + @Override + public String toString() { + return String.format("CopyObjectResult{%s}", stringify()); } } diff --git a/api/src/main/java/io/minio/messages/CopyPartResult.java b/api/src/main/java/io/minio/messages/CopyPartResult.java index 6c6ad3c80..71ba090b7 100644 --- a/api/src/main/java/io/minio/messages/CopyPartResult.java +++ b/api/src/main/java/io/minio/messages/CopyPartResult.java @@ -21,10 +21,15 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of UploadPartCopy * API. */ @Root(name = "CopyPartResult", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class CopyPartResult extends CopyObjectResult {} +public class CopyPartResult extends CopyObjectResult { + @Override + public String toString() { + return String.format("CopyPartResult{%s}", super.stringify()); + } +} diff --git a/api/src/main/java/io/minio/messages/CreateBucketConfiguration.java b/api/src/main/java/io/minio/messages/CreateBucketConfiguration.java index 415498b5c..5d3063346 100644 --- a/api/src/main/java/io/minio/messages/CreateBucketConfiguration.java +++ b/api/src/main/java/io/minio/messages/CreateBucketConfiguration.java @@ -21,7 +21,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of CreateBucket * API. */ @@ -49,6 +49,7 @@ public CreateBucketConfiguration(String locationConstraint, Location location, B this.bucket = bucket; } + /** Bucket location information of {@link CreateBucketConfiguration}. */ @Root(name = "Location", strict = false) @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public static class Location { @@ -64,6 +65,7 @@ public Location(String name, String type) { } } + /** Bucket properties of {@link CreateBucketConfiguration}. */ @Root(name = "Bucket", strict = false) @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public static class Bucket { diff --git a/api/src/main/java/io/minio/messages/CsvInputSerialization.java b/api/src/main/java/io/minio/messages/CsvInputSerialization.java deleted file mode 100644 index 843bf57c8..000000000 --- a/api/src/main/java/io/minio/messages/CsvInputSerialization.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote CSV input serialization request XML as per {@link - * SelectObjectContentRequest}. - */ -@Root(name = "CSV") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class CsvInputSerialization { - @Element(name = "AllowQuotedRecordDelimiter", required = false) - private boolean allowQuotedRecordDelimiter; - - @Element(name = "Comments", required = false) - private Character comments; - - @Element(name = "FieldDelimiter", required = false) - private Character fieldDelimiter; - - @Element(name = "FileHeaderInfo", required = false) - private FileHeaderInfo fileHeaderInfo; - - @Element(name = "QuoteCharacter", required = false) - private Character quoteCharacter; - - @Element(name = "QuoteEscapeCharacter", required = false) - private Character quoteEscapeCharacter; - - @Element(name = "RecordDelimiter", required = false) - private Character recordDelimiter; - - /** Constructs a new CsvInputSerialization object. */ - public CsvInputSerialization( - boolean allowQuotedRecordDelimiter, - Character comments, - Character fieldDelimiter, - FileHeaderInfo fileHeaderInfo, - Character quoteCharacter, - Character quoteEscapeCharacter, - Character recordDelimiter) { - this.allowQuotedRecordDelimiter = allowQuotedRecordDelimiter; - this.comments = comments; - this.fieldDelimiter = fieldDelimiter; - this.fileHeaderInfo = fileHeaderInfo; - this.quoteCharacter = quoteCharacter; - this.quoteEscapeCharacter = quoteEscapeCharacter; - this.recordDelimiter = recordDelimiter; - } -} diff --git a/api/src/main/java/io/minio/messages/CsvOutputSerialization.java b/api/src/main/java/io/minio/messages/CsvOutputSerialization.java deleted file mode 100644 index 40a46a3bc..000000000 --- a/api/src/main/java/io/minio/messages/CsvOutputSerialization.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote CSV output serialization request XML as per {@link - * SelectObjectContentRequest}. - */ -@Root(name = "CSV") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class CsvOutputSerialization { - @Element(name = "FieldDelimiter", required = false) - private Character fieldDelimiter; - - @Element(name = "QuoteCharacter", required = false) - private Character quoteCharacter; - - @Element(name = "QuoteEscapeCharacter", required = false) - private Character quoteEscapeCharacter; - - @Element(name = "QuoteFields", required = false) - private QuoteFields quoteFields; - - @Element(name = "RecordDelimiter", required = false) - private Character recordDelimiter; - - /** Constructs a new CsvOutputSerialization object. */ - public CsvOutputSerialization( - Character fieldDelimiter, - Character quoteCharacter, - Character quoteEscapeCharacter, - QuoteFields quoteFields, - Character recordDelimiter) { - this.fieldDelimiter = fieldDelimiter; - this.quoteCharacter = quoteCharacter; - this.quoteEscapeCharacter = quoteEscapeCharacter; - this.quoteFields = quoteFields; - this.recordDelimiter = recordDelimiter; - } -} diff --git a/api/src/main/java/io/minio/messages/DateDays.java b/api/src/main/java/io/minio/messages/DateDays.java deleted file mode 100644 index 03eda56ad..000000000 --- a/api/src/main/java/io/minio/messages/DateDays.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.time.ZonedDateTime; -import org.simpleframework.xml.Element; - -/** Base class for {@link Transition} and {@link Expiration}. */ -public abstract class DateDays { - @Element(name = "Date", required = false) - protected ResponseDate date; - - @Element(name = "Days", required = false) - protected Integer days; - - public ZonedDateTime date() { - return (date != null) ? date.zonedDateTime() : null; - } - - public Integer days() { - return days; - } -} diff --git a/api/src/main/java/io/minio/messages/DeleteError.java b/api/src/main/java/io/minio/messages/DeleteError.java deleted file mode 100644 index c4c9a51ba..000000000 --- a/api/src/main/java/io/minio/messages/DeleteError.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Namespace; -import org.simpleframework.xml.Root; - -/** Helper class to denote error for {@link DeleteResult}. */ -@Root(name = "Error", strict = false) -@Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class DeleteError extends ErrorResponse { - private static final long serialVersionUID = 1905162041950251407L; // fix SE_BAD_FIELD -} diff --git a/api/src/main/java/io/minio/messages/DeleteMarkerReplication.java b/api/src/main/java/io/minio/messages/DeleteMarkerReplication.java deleted file mode 100644 index 9141fc2fa..000000000 --- a/api/src/main/java/io/minio/messages/DeleteMarkerReplication.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote delete marker replication information for {@link ReplicationRule}. */ -@Root(name = "DeleteMarkerReplication") -public class DeleteMarkerReplication { - @Element(name = "Status", required = false) - private Status status; - - /** Constructs new server-side encryption configuration rule. */ - public DeleteMarkerReplication( - @Nullable @Element(name = "Status", required = false) Status status) { - this.status = (status == null) ? Status.DISABLED : status; - } - - public Status status() { - return status; - } -} diff --git a/api/src/main/java/io/minio/messages/DeleteObject.java b/api/src/main/java/io/minio/messages/DeleteObject.java deleted file mode 100644 index 136a9a6b1..000000000 --- a/api/src/main/java/io/minio/messages/DeleteObject.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import io.minio.Time; -import java.time.ZonedDateTime; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; -import org.simpleframework.xml.convert.Converter; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.OutputNode; - -/** Helper class to denote Object information for {@link DeleteRequest}. */ -@Root(name = "Object") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class DeleteObject { - @Element(name = "Key") - private String name; - - @Element(name = "VersionId", required = false) - private String versionId; - - @Element(name = "ETag", required = false) - private String etag; - - @Element(name = "LastModifiedTime", required = false) - private HttpHeaderDate lastModifiedTime; - - @Element(name = "Size", required = false) - private Long size; - - public DeleteObject(String name) { - this.name = name; - } - - public DeleteObject(String name, String versionId) { - this(name); - this.versionId = versionId; - } - - public DeleteObject( - String name, String versionId, String etag, ZonedDateTime lastModifiedTime, Long size) { - this(name, versionId); - this.etag = etag; - this.lastModifiedTime = lastModifiedTime == null ? null : new HttpHeaderDate(lastModifiedTime); - this.size = size; - } - - /** HTTP header date wrapping {@link ZonedDateTime}. */ - @Root - @Convert(HttpHeaderDate.HttpHeaderDateConverter.class) - public static class HttpHeaderDate { - private ZonedDateTime zonedDateTime; - - public HttpHeaderDate(ZonedDateTime zonedDateTime) { - this.zonedDateTime = zonedDateTime; - } - - public String toString() { - return zonedDateTime.format(Time.HTTP_HEADER_DATE_FORMAT); - } - - public static HttpHeaderDate fromString(String dateString) { - return new HttpHeaderDate(ZonedDateTime.parse(dateString, Time.HTTP_HEADER_DATE_FORMAT)); - } - - /** XML converter class. */ - public static class HttpHeaderDateConverter implements Converter { - @Override - public HttpHeaderDate read(InputNode node) throws Exception { - return HttpHeaderDate.fromString(node.getValue()); - } - - @Override - public void write(OutputNode node, HttpHeaderDate date) { - node.setValue(date.toString()); - } - } - } -} diff --git a/api/src/main/java/io/minio/messages/DeleteReplication.java b/api/src/main/java/io/minio/messages/DeleteReplication.java deleted file mode 100644 index c24ce7437..000000000 --- a/api/src/main/java/io/minio/messages/DeleteReplication.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote delete replication information for {@link ReplicationRule}. This is MinIO - * specific extension. - */ -@Root(name = "DeleteReplication") -public class DeleteReplication { - @Element(name = "Status", required = false) - private Status status; - - public DeleteReplication(@Nullable @Element(name = "Status", required = false) Status status) { - this.status = (status == null) ? Status.DISABLED : status; - } - - public Status status() { - return status; - } -} diff --git a/api/src/main/java/io/minio/messages/DeleteRequest.java b/api/src/main/java/io/minio/messages/DeleteRequest.java index eef72d46a..41e65ea4e 100644 --- a/api/src/main/java/io/minio/messages/DeleteRequest.java +++ b/api/src/main/java/io/minio/messages/DeleteRequest.java @@ -16,7 +16,9 @@ package io.minio.messages; +import io.minio.Time; import io.minio.Utils; +import java.time.ZonedDateTime; import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; @@ -24,9 +26,13 @@ import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; +import org.simpleframework.xml.convert.Converter; +import org.simpleframework.xml.stream.InputNode; +import org.simpleframework.xml.stream.OutputNode; /** - * Object representation of request XML of DeleteObjects * API. */ @@ -38,12 +44,82 @@ public class DeleteRequest { private boolean quiet; @ElementList(name = "Object", inline = true) - private List objectList; + private List objects; /** Constructs new delete request for given object list and quiet flag. */ - public DeleteRequest(@Nonnull List objectList, boolean quiet) { - this.objectList = - Utils.unmodifiableList(Objects.requireNonNull(objectList, "Object list must not be null")); + public DeleteRequest(@Nonnull List objects, boolean quiet) { + this.objects = + Utils.unmodifiableList(Objects.requireNonNull(objects, "Object list must not be null")); this.quiet = quiet; } + + /** Object information of {@link DeleteRequest}. */ + @Root(name = "Object") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class Object { + @Element(name = "Key") + private String name; + + @Element(name = "VersionId", required = false) + private String versionId; + + @Element(name = "ETag", required = false) + private String etag; + + @Element(name = "LastModifiedTime", required = false) + private HttpHeaderDate lastModifiedTime; + + @Element(name = "Size", required = false) + private Long size; + + public Object(String name) { + this.name = name; + } + + public Object(String name, String versionId) { + this(name); + this.versionId = versionId; + } + + public Object( + String name, String versionId, String etag, ZonedDateTime lastModifiedTime, Long size) { + this(name, versionId); + this.etag = etag; + this.lastModifiedTime = + lastModifiedTime == null ? null : new HttpHeaderDate(lastModifiedTime); + this.size = size; + } + + /** HTTP header date wrapping {@link ZonedDateTime}. */ + @Root + @Convert(HttpHeaderDate.HttpHeaderDateConverter.class) + public static class HttpHeaderDate { + private ZonedDateTime zonedDateTime; + + public HttpHeaderDate(ZonedDateTime zonedDateTime) { + this.zonedDateTime = zonedDateTime; + } + + public String toString() { + return zonedDateTime.format(Time.HTTP_HEADER_DATE_FORMAT); + } + + public static HttpHeaderDate fromString(String dateString) { + return new HttpHeaderDate(ZonedDateTime.parse(dateString, Time.HTTP_HEADER_DATE_FORMAT)); + } + + /** XML converter of {@link DeleteRequest.Object.HttpHeaderDate}. */ + public static class HttpHeaderDateConverter implements Converter { + @Override + public HttpHeaderDate read(InputNode node) throws Exception { + return HttpHeaderDate.fromString(node.getValue()); + } + + @Override + public void write(OutputNode node, HttpHeaderDate date) { + node.setValue(date.toString()); + } + } + } + } } diff --git a/api/src/main/java/io/minio/messages/DeleteResult.java b/api/src/main/java/io/minio/messages/DeleteResult.java index c5c1a04e1..5c1035b78 100644 --- a/api/src/main/java/io/minio/messages/DeleteResult.java +++ b/api/src/main/java/io/minio/messages/DeleteResult.java @@ -19,12 +19,13 @@ import io.minio.Utils; import java.util.LinkedList; import java.util.List; +import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of response XML of DeleteObjects * API. */ @@ -32,26 +33,88 @@ @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") public class DeleteResult { @ElementList(name = "Deleted", inline = true, required = false) - private List objectList; + private List objects; @ElementList(name = "Error", inline = true, required = false) - private List errorList; + private List errors; public DeleteResult() {} /** Constructs new delete result with an error. */ - public DeleteResult(DeleteError error) { - this.errorList = new LinkedList(); - this.errorList.add(error); + public DeleteResult(Error error) { + this.errors = new LinkedList(); + this.errors.add(error); } /** Returns deleted object list. */ - public List objectList() { - return Utils.unmodifiableList(objectList); + public List objects() { + return Utils.unmodifiableList(objects); } /** Returns delete error list. */ - public List errorList() { - return Utils.unmodifiableList(errorList); + public List errors() { + return Utils.unmodifiableList(errors); + } + + @Override + public String toString() { + return String.format( + "DeleteResult{objects=%s, errors=%s}", Utils.stringify(objects), Utils.stringify(errors)); + } + + /** Deleted object of {@link DeleteResult}. */ + @Root(name = "Deleted", strict = false) + public static class Deleted { + @Element(name = "Key") + private String name; + + @Element(name = "VersionId", required = false) + private String versionId; + + @Element(name = "DeleteMarker", required = false) + private boolean deleteMarker; + + @Element(name = "DeleteMarkerVersionId", required = false) + private String deleteMarkerVersionId; + + public Deleted() {} + + public String name() { + return name; + } + + public String versionId() { + return versionId; + } + + public boolean deleteMarker() { + return deleteMarker; + } + + public String deleteMarkerVersionId() { + return deleteMarkerVersionId; + } + + @Override + public String toString() { + return String.format( + "Deleted{name=%s, versionId=%s, deleteMarker=%s, deleteMarkerVersionId=%s}", + Utils.stringify(name), + Utils.stringify(versionId), + Utils.stringify(deleteMarker), + Utils.stringify(deleteMarkerVersionId)); + } + } + + /** Error information of {@link DeleteResult}. */ + @Root(name = "Error", strict = false) + @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") + public static class Error extends ErrorResponse { + private static final long serialVersionUID = 1905162041950251407L; // fix SE_BAD_FIELD + + @Override + public String toString() { + return String.format("Error{%s}", super.stringify()); + } } } diff --git a/api/src/main/java/io/minio/messages/DeletedObject.java b/api/src/main/java/io/minio/messages/DeletedObject.java deleted file mode 100644 index 8338909e5..000000000 --- a/api/src/main/java/io/minio/messages/DeletedObject.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote deleted object for {@link DeleteResult}. */ -@Root(name = "Deleted", strict = false) -public class DeletedObject { - @Element(name = "Key") - private String name; - - @Element(name = "VersionId", required = false) - private String versionId; - - @Element(name = "DeleteMarker", required = false) - private boolean deleteMarker; - - @Element(name = "DeleteMarkerVersionId", required = false) - private String deleteMarkerVersionId; - - public DeletedObject() {} - - public String name() { - return name; - } - - public String versionId() { - return versionId; - } - - public boolean deleteMarker() { - return deleteMarker; - } - - public String deleteMarkerVersionId() { - return deleteMarkerVersionId; - } -} diff --git a/api/src/main/java/io/minio/messages/Encryption.java b/api/src/main/java/io/minio/messages/Encryption.java deleted file mode 100644 index b37f34c9c..000000000 --- a/api/src/main/java/io/minio/messages/Encryption.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote encryption information of {@link S3OutputLocation}. */ -@Root(name = "Encryption") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class Encryption { - @Element(name = "EncryptionType") - private SseAlgorithm encryptionType; - - @Element(name = "KMSContext", required = false) - private String kmsContext; - - @Element(name = "KMSKeyId", required = false) - private String kmsKeyId; - - public Encryption( - @Nonnull SseAlgorithm encryptionType, - @Nullable String kmsContext, - @Nullable String kmsKeyId) { - this.encryptionType = - Objects.requireNonNull(encryptionType, "Encryption type must not be null"); - this.kmsContext = kmsContext; - this.kmsKeyId = kmsKeyId; - } -} diff --git a/api/src/main/java/io/minio/messages/EncryptionConfiguration.java b/api/src/main/java/io/minio/messages/EncryptionConfiguration.java deleted file mode 100644 index fb641c5a9..000000000 --- a/api/src/main/java/io/minio/messages/EncryptionConfiguration.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote encryption configuration information for {@link ReplicationDestination}. - */ -@Root(name = "EncryptionConfiguration") -public class EncryptionConfiguration { - @Element(name = "ReplicaKmsKeyID", required = false) - private String replicaKmsKeyID; - - public EncryptionConfiguration( - @Nullable @Element(name = "ReplicaKmsKeyID", required = false) String replicaKmsKeyID) { - this.replicaKmsKeyID = replicaKmsKeyID; - } - - public String replicaKmsKeyID() { - return this.replicaKmsKeyID; - } -} diff --git a/api/src/main/java/io/minio/messages/ErrorResponse.java b/api/src/main/java/io/minio/messages/ErrorResponse.java index 5e45f2bfb..f0477251b 100644 --- a/api/src/main/java/io/minio/messages/ErrorResponse.java +++ b/api/src/main/java/io/minio/messages/ErrorResponse.java @@ -16,12 +16,13 @@ package io.minio.messages; +import io.minio.Utils; import java.io.Serializable; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; -/** Object representation of error response XML of any S3 REST APIs. */ +/** Error response XML of any S3 REST APIs. */ @Root(name = "ErrorResponse", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") public class ErrorResponse implements Serializable { @@ -106,28 +107,21 @@ public String resource() { return resource; } - /** Returns string representation of this object. */ + protected String stringify() { + return String.format( + "code=%s, message=%s, bucketName=%s, objectName=%s, resource=%s," + + " requestId=%s, hostId=%s", + Utils.stringify(code), + Utils.stringify(message), + Utils.stringify(bucketName), + Utils.stringify(objectName), + Utils.stringify(resource), + Utils.stringify(requestId), + Utils.stringify(hostId)); + } + + @Override public String toString() { - return "ErrorResponse(code = " - + code - + ", " - + "message = " - + message - + ", " - + "bucketName = " - + bucketName - + ", " - + "objectName = " - + objectName - + ", " - + "resource = " - + resource - + ", " - + "requestId = " - + requestId - + ", " - + "hostId = " - + hostId - + ")"; + return String.format("ErrorResponse{%s}", stringify()); } } diff --git a/api/src/main/java/io/minio/messages/Event.java b/api/src/main/java/io/minio/messages/Event.java deleted file mode 100644 index 7e59e22aa..000000000 --- a/api/src/main/java/io/minio/messages/Event.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2018 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.minio.Utils; -import java.time.ZonedDateTime; -import java.util.Map; - -/** Helper class to denote single event record for {@link NotificationRecords}. */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = "UuF", - justification = "eventVersion and eventSource are available for completeness") -public class Event { - @JsonProperty private String eventVersion; - @JsonProperty private String eventSource; - @JsonProperty private String awsRegion; - @JsonProperty private EventType eventName; - @JsonProperty private Identity userIdentity; - @JsonProperty private Map requestParameters; - @JsonProperty private Map responseElements; - @JsonProperty private EventMetadata s3; - @JsonProperty private Source source; - @JsonProperty private ResponseDate eventTime; - - public String region() { - return awsRegion; - } - - public ZonedDateTime eventTime() { - return eventTime.zonedDateTime(); - } - - public EventType eventType() { - return eventName; - } - - public String userId() { - if (userIdentity == null) { - return null; - } - - return userIdentity.principalId(); - } - - public Map requestParameters() { - return Utils.unmodifiableMap(requestParameters); - } - - public Map responseElements() { - return Utils.unmodifiableMap(responseElements); - } - - public String bucketName() { - if (s3 == null) { - return null; - } - - return s3.bucketName(); - } - - public String bucketOwner() { - if (s3 == null) { - return null; - } - - return s3.bucketOwner(); - } - - public String bucketArn() { - if (s3 == null) { - return null; - } - - return s3.bucketArn(); - } - - public String objectName() { - if (s3 == null) { - return null; - } - - return s3.objectName(); - } - - public long objectSize() { - if (s3 == null) { - return -1; - } - - return s3.objectSize(); - } - - public String etag() { - if (s3 == null) { - return null; - } - - return s3.etag(); - } - - public String objectVersionId() { - if (s3 == null) { - return null; - } - - return s3.objectVersionId(); - } - - public String sequencer() { - if (s3 == null) { - return null; - } - - return s3.sequencer(); - } - - public Map userMetadata() { - if (s3 == null) { - return null; - } - - return s3.userMetadata(); - } - - public String host() { - if (source == null) { - return null; - } - - return source.host(); - } - - public String port() { - if (source == null) { - return null; - } - - return source.port(); - } - - public String userAgent() { - if (source == null) { - return null; - } - - return source.userAgent(); - } -} diff --git a/api/src/main/java/io/minio/messages/EventMetadata.java b/api/src/main/java/io/minio/messages/EventMetadata.java deleted file mode 100644 index 35811ca05..000000000 --- a/api/src/main/java/io/minio/messages/EventMetadata.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2020 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Map; - -/** Helper class to denote event metadata for {@link EventMetadata}. */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = {"UwF", "UuF"}, - justification = - "Everything in this class is initialized by JSON unmarshalling " - + "and s3SchemaVersion/configurationId are available for completeness.") -public class EventMetadata { - @JsonProperty private String s3SchemaVersion; - @JsonProperty private String configurationId; - @JsonProperty private BucketMetadata bucket; - @JsonProperty private ObjectMetadata object; - - public String bucketName() { - if (bucket == null) { - return null; - } - - return bucket.name(); - } - - public String bucketOwner() { - if (bucket == null) { - return null; - } - - return bucket.owner(); - } - - public String bucketArn() { - if (bucket == null) { - return null; - } - - return bucket.arn(); - } - - public String objectName() { - if (object == null) { - return null; - } - - return object.key(); - } - - public long objectSize() { - if (object == null) { - return -1; - } - - return object.size(); - } - - public String etag() { - if (object == null) { - return null; - } - - return object.etag(); - } - - public String objectVersionId() { - if (object == null) { - return null; - } - - return object.versionId(); - } - - public String sequencer() { - if (object == null) { - return null; - } - - return object.sequencer(); - } - - public Map userMetadata() { - if (object == null) { - return null; - } - - return object.userMetadata(); - } -} diff --git a/api/src/main/java/io/minio/messages/EventType.java b/api/src/main/java/io/minio/messages/EventType.java index 1e7965c28..f31999919 100644 --- a/api/src/main/java/io/minio/messages/EventType.java +++ b/api/src/main/java/io/minio/messages/EventType.java @@ -23,7 +23,7 @@ import org.simpleframework.xml.stream.InputNode; import org.simpleframework.xml.stream.OutputNode; -/** Amazon AWS S3 event types for notifications. */ +/** S3 event type. */ @Root(name = "Event") @Convert(EventType.EventTypeConverter.class) public enum EventType { @@ -72,7 +72,7 @@ public static EventType fromString(String eventTypeString) { throw new IllegalArgumentException("unknown event '" + eventTypeString + "'"); } - /** XML converter class. */ + /** XML converter of {@link EventType}. */ public static class EventTypeConverter implements Converter { @Override public EventType read(InputNode node) throws Exception { diff --git a/api/src/main/java/io/minio/messages/ExistingObjectReplication.java b/api/src/main/java/io/minio/messages/ExistingObjectReplication.java deleted file mode 100644 index d4b4aa01f..000000000 --- a/api/src/main/java/io/minio/messages/ExistingObjectReplication.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote existing object replication information for {@link ReplicationRule}. */ -@Root(name = "ExistingObjectReplication") -public class ExistingObjectReplication { - @Element(name = "Status") - private Status status; - - public ExistingObjectReplication(@Nonnull @Element(name = "Status") Status status) { - this.status = Objects.requireNonNull(status, "Status must not be null"); - } - - public Status status() { - return this.status; - } -} diff --git a/api/src/main/java/io/minio/messages/Expiration.java b/api/src/main/java/io/minio/messages/Expiration.java deleted file mode 100644 index b2fc13541..000000000 --- a/api/src/main/java/io/minio/messages/Expiration.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.time.ZonedDateTime; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote expiration information for {@link LifecycleRule}. */ -@Root(name = "Expiration") -public class Expiration extends DateDays { - @Element(name = "ExpiredObjectDeleteMarker", required = false) - private Boolean expiredObjectDeleteMarker; - - @Element(name = "ExpiredObjectAllVersions", required = false) - private Boolean expiredObjectAllVersions; // This is MinIO specific extension. - - public Expiration( - @Nullable @Element(name = "Date", required = false) ResponseDate date, - @Nullable @Element(name = "Days", required = false) Integer days, - @Nullable @Element(name = "ExpiredObjectDeleteMarker", required = false) - Boolean expiredObjectDeleteMarker) { - if (expiredObjectDeleteMarker != null) { - if (date != null || days != null) { - throw new IllegalArgumentException( - "ExpiredObjectDeleteMarker must not be provided along with Date and Days"); - } - } else if (date != null ^ days != null) { - this.date = date; - this.days = days; - } else { - throw new IllegalArgumentException("Only one of date or days must be set"); - } - - this.expiredObjectDeleteMarker = expiredObjectDeleteMarker; - } - - public Expiration(ZonedDateTime date, Integer days, Boolean expiredObjectDeleteMarker) { - this(date == null ? null : new ResponseDate(date), days, expiredObjectDeleteMarker); - } - - public Expiration( - @Nullable @Element(name = "Date", required = false) ResponseDate date, - @Nullable @Element(name = "Days", required = false) Integer days, - @Nullable @Element(name = "ExpiredObjectDeleteMarker", required = false) - Boolean expiredObjectDeleteMarker, - @Element(name = "ExpiredObjectAllVersions", required = false) - Boolean expiredObjectAllVersions) { - this(date, days, expiredObjectDeleteMarker); - this.expiredObjectAllVersions = expiredObjectAllVersions; - } - - public Boolean expiredObjectDeleteMarker() { - return expiredObjectDeleteMarker; - } - - /** This is MinIO specific extension. */ - public Boolean expiredObjectAllVersions() { - return expiredObjectAllVersions; - } -} diff --git a/api/src/main/java/io/minio/messages/FileHeaderInfo.java b/api/src/main/java/io/minio/messages/FileHeaderInfo.java deleted file mode 100644 index 46943f18f..000000000 --- a/api/src/main/java/io/minio/messages/FileHeaderInfo.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -/** Description the first line of input in CSV object. */ -public enum FileHeaderInfo { - USE, - IGNORE, - NONE; -} diff --git a/api/src/main/java/io/minio/messages/Filter.java b/api/src/main/java/io/minio/messages/Filter.java index dce52114c..b3dbe21dc 100644 --- a/api/src/main/java/io/minio/messages/Filter.java +++ b/api/src/main/java/io/minio/messages/Filter.java @@ -1,5 +1,5 @@ /* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, Inc. + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2025 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,56 +17,233 @@ package io.minio.messages; import io.minio.Utils; -import java.util.LinkedList; -import java.util.List; -import org.simpleframework.xml.ElementList; +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.simpleframework.xml.Element; +import org.simpleframework.xml.ElementMap; import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; /** - * Helper class to denote Filter configuration of {@link CloudFunctionConfiguration}, {@link - * QueueConfiguration} or {@link TopicConfiguration}. + * Filter information for {@link ReplicationConfiguration.Rule} and {@link + * LifecycleConfiguration.Rule}. */ -@Root(name = "Filter", strict = false) +@Root(name = "Filter") public class Filter { - @ElementList(name = "S3Key") - private List filterRuleList; - - public Filter() {} - - /** - * Sets filter rule to list. As per Amazon AWS S3 server behavior, its not possible to set more - * than one rule for "prefix" or "suffix". However the spec - * http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTnotification.html is not clear - * about this behavior. - */ - private void setRule(String name, String value) throws IllegalArgumentException { - if (value.length() > 1024) { - throw new IllegalArgumentException("value '" + value + "' is more than 1024 long"); - } + @Element(name = "And", required = false) + private And andOperator; - if (filterRuleList == null) { - filterRuleList = new LinkedList<>(); - } + @Element(name = "Prefix", required = false) + @Convert(PrefixConverter.class) + private String prefix; - for (FilterRule rule : filterRuleList) { - // Remove rule.name is same as given name. - if (rule.name().equals(name)) { - filterRuleList.remove(rule); - } + @Element(name = "Tag", required = false) + private Tag tag; + + @Element(name = "ObjectSizeLessThan", required = false) + private Long objectSizeLessThan; + + @Element(name = "ObjectSizeGreaterThan", required = false) + private Long objectSizeGreaterThan; + + public Filter( + @Nullable @Element(name = "And", required = false) And andOperator, + @Nullable @Element(name = "Prefix", required = false) String prefix, + @Nullable @Element(name = "Tag", required = false) Tag tag) { + if (andOperator != null ^ prefix != null ^ tag != null) { + this.andOperator = andOperator; + this.prefix = prefix; + this.tag = tag; + } else { + throw new IllegalArgumentException("Only one of And, Prefix or Tag must be set"); } + } + + public Filter( + @Nullable @Element(name = "And", required = false) And andOperator, + @Nullable @Element(name = "Prefix", required = false) String prefix, + @Nullable @Element(name = "Tag", required = false) Tag tag, + @Nullable @Element(name = "ObjectSizeLessThan", required = false) Long objectSizeLessThan, + @Nullable @Element(name = "ObjectSizeGreaterThan", required = false) + Long objectSizeGreaterThan) { + this(andOperator, prefix, tag); + this.objectSizeLessThan = objectSizeLessThan; + this.objectSizeGreaterThan = objectSizeGreaterThan; + } + + public Filter(@Nonnull And andOperator) { + this.andOperator = Objects.requireNonNull(andOperator, "And operator must not be null"); + } + + public Filter(@Nonnull String prefix) { + this.prefix = Objects.requireNonNull(prefix, "Prefix must not be null"); + } + + public Filter(@Nonnull Tag tag) { + this.tag = Objects.requireNonNull(tag, "Tag must not be null"); + } + + public And andOperator() { + return this.andOperator; + } + + public String prefix() { + return this.prefix; + } + + public Tag tag() { + return this.tag; + } - filterRuleList.add(new FilterRule(name, value)); + public Long objectSizeLessThan() { + return this.objectSizeLessThan; } - public void setPrefixRule(String value) throws IllegalArgumentException { - setRule("prefix", value); + public Long objectSizeGreaterThan() { + return this.objectSizeGreaterThan; } - public void setSuffixRule(String value) throws IllegalArgumentException { - setRule("suffix", value); + @Override + public String toString() { + return String.format( + "Filter{andOperator=%s, prefix=%s, tag=%s, objectSizeLessThan=%s," + + " objectSizeGreaterThan=%s}", + Utils.stringify(andOperator), + Utils.stringify(prefix), + Utils.stringify(tag), + Utils.stringify(objectSizeLessThan), + Utils.stringify(objectSizeGreaterThan)); } - public List filterRuleList() { - return Utils.unmodifiableList(filterRuleList); + /** AND operator of {@link Filter}. */ + @Root(name = "And") + public static class And { + @Element(name = "Prefix", required = false) + @Convert(PrefixConverter.class) + private String prefix; + + @Element(name = "ObjectSizeLessThan", required = false) + private Long objectSizeLessThan; + + @Element(name = "ObjectSizeGreaterThan", required = false) + private Long objectSizeGreaterThan; + + @ElementMap( + attribute = false, + entry = "Tag", + inline = true, + key = "Key", + value = "Value", + required = false) + private Map tags; + + public And( + @Nullable @Element(name = "Prefix", required = false) String prefix, + @Nullable + @ElementMap( + attribute = false, + entry = "Tag", + inline = true, + key = "Key", + value = "Value", + required = false) + Map tags) { + if (prefix == null && tags == null) { + throw new IllegalArgumentException("At least Prefix or Tags must be set"); + } + + if (tags != null) { + for (String key : tags.keySet()) { + if (key.isEmpty()) { + throw new IllegalArgumentException("Tags must not contain empty key"); + } + } + } + + this.prefix = prefix; + this.tags = Utils.unmodifiableMap(tags); + } + + public And( + @Nullable @Element(name = "Prefix", required = false) String prefix, + @Nullable + @ElementMap( + attribute = false, + entry = "Tag", + inline = true, + key = "Key", + value = "Value", + required = false) + Map tags, + @Nullable @Element(name = "ObjectSizeLessThan", required = false) Long objectSizeLessThan, + @Nullable @Element(name = "ObjectSizeGreaterThan", required = false) + Long objectSizeGreaterThan) { + this(prefix, tags); + this.objectSizeLessThan = objectSizeLessThan; + this.objectSizeGreaterThan = objectSizeGreaterThan; + } + + public String prefix() { + return this.prefix; + } + + public Long objectSizeLessThan() { + return this.objectSizeLessThan; + } + + public Long objectSizeGreaterThan() { + return this.objectSizeGreaterThan; + } + + public Map tags() { + return this.tags; + } + + @Override + public String toString() { + return String.format( + "And{prefix=%s, objectSizeLessThan=%s, objectSizeGreaterThan=%s, tags=%s}", + Utils.stringify(prefix), + Utils.stringify(objectSizeLessThan), + Utils.stringify(objectSizeGreaterThan), + Utils.stringify(tags)); + } + } + + /** Tag information of {@link Filter}. */ + @Root(name = "Tag") + public static class Tag { + @Element(name = "Key") + private String key; + + @Element(name = "Value") + private String value; + + public Tag( + @Nonnull @Element(name = "Key") String key, + @Nonnull @Element(name = "Value") String value) { + Objects.requireNonNull(key, "Key must not be null"); + if (key.isEmpty()) { + throw new IllegalArgumentException("Key must not be empty"); + } + + this.key = key; + this.value = Objects.requireNonNull(value, "Value must not be null"); + } + + public String key() { + return this.key; + } + + public String value() { + return this.value; + } + + @Override + public String toString() { + return String.format("Tag{key=%s, value=%s}", Utils.stringify(key), Utils.stringify(value)); + } } } diff --git a/api/src/main/java/io/minio/messages/FilterRule.java b/api/src/main/java/io/minio/messages/FilterRule.java deleted file mode 100644 index 4eef68a27..000000000 --- a/api/src/main/java/io/minio/messages/FilterRule.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote FilterRule configuration of {@link CloudFunctionConfiguration}, {@link - * QueueConfiguration} or {@link TopicConfiguration}. - */ -@Root(name = "FilterRule", strict = false) -public class FilterRule { - @Element(name = "Name") - private String name; - - @Element(name = "Value") - private String value; - - public FilterRule() {} - - public FilterRule(String name, String value) { - this.name = name; - this.value = value; - } - - /** Returns filter name. */ - public String name() { - return name; - } - - /** Returns filter value. */ - public String value() { - return value; - } -} diff --git a/api/src/main/java/io/minio/messages/GetObjectAttributesOutput.java b/api/src/main/java/io/minio/messages/GetObjectAttributesOutput.java index f1b259763..35da68b5e 100644 --- a/api/src/main/java/io/minio/messages/GetObjectAttributesOutput.java +++ b/api/src/main/java/io/minio/messages/GetObjectAttributesOutput.java @@ -18,14 +18,12 @@ import io.minio.Utils; import java.time.ZonedDateTime; -import java.util.List; import org.simpleframework.xml.Element; -import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of response XML of GetObjectAttributes * API. */ @@ -97,50 +95,39 @@ public Long objectSize() { return objectSize; } - @Root(name = "ObjectParts", strict = false) - public static class ObjectParts { - @Element(name = "IsTruncated", required = false) - private boolean isTruncated; - - @Element(name = "MaxParts", required = false) - private Integer maxParts; - - @Element(name = "NextPartNumberMarker", required = false) - private Integer nextPartNumberMarker; - - @Element(name = "PartNumberMarker", required = false) - private Integer partNumberMarker; - - @ElementList(name = "Part", inline = true, required = false) - private List parts; + @Override + public String toString() { + return String.format( + "GetObjectAttributesOutput{etag=%s, checksum=%s, objectParts=%s, storageClass=%s," + + " objectSize=%s, deleteMarker=%s, lastModified=%s, versionId=%s}", + Utils.stringify(etag), + Utils.stringify(checksum), + Utils.stringify(objectParts), + Utils.stringify(storageClass), + Utils.stringify(objectSize), + Utils.stringify(deleteMarker), + Utils.stringify(lastModified), + Utils.stringify(versionId)); + } + /** Object part information of {@link GetObjectAttributesOutput}. */ + @Root(name = "ObjectParts", strict = false) + public static class ObjectParts extends BasePartsResult { @Element(name = "PartsCount", required = false) private Integer partsCount; - public ObjectParts() {} - - public boolean isTruncated() { - return isTruncated; - } - - public Integer maxParts() { - return maxParts; - } - - public Integer nextPartNumberMarker() { - return nextPartNumberMarker; - } - - public Integer partNumberMarker() { - return partNumberMarker; - } - - public List parts() { - return Utils.unmodifiableList(parts); + public ObjectParts() { + super(); } public Integer partsCount() { return partsCount; } + + @Override + public String toString() { + return String.format( + "ObjectParts{partsCount=%s, %s}", Utils.stringify(partsCount), super.toString()); + } } } diff --git a/api/src/main/java/io/minio/messages/GlacierJobParameters.java b/api/src/main/java/io/minio/messages/GlacierJobParameters.java deleted file mode 100644 index 6e894e7b3..000000000 --- a/api/src/main/java/io/minio/messages/GlacierJobParameters.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote S3 Glacier job parameters of {@link RestoreRequest}. */ -@Root(name = "GlacierJobParameters") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class GlacierJobParameters { - @Element(name = "Tier") - private Tier tier; - - public GlacierJobParameters(@Nonnull Tier tier) { - this.tier = Objects.requireNonNull(tier, "Tier must not be null"); - } -} diff --git a/api/src/main/java/io/minio/messages/Grant.java b/api/src/main/java/io/minio/messages/Grant.java deleted file mode 100644 index 940240447..000000000 --- a/api/src/main/java/io/minio/messages/Grant.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote grant information of {@link AccessControlList}. */ -@Root(name = "Grant") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class Grant { - @Element(name = "Grantee", required = false) - private Grantee grantee; - - @Element(name = "Permission", required = false) - private Permission permission; - - public Grant( - @Nullable @Element(name = "Grantee", required = false) Grantee grantee, - @Nullable @Element(name = "Permission", required = false) Permission permission) { - if (grantee == null && permission == null) { - throw new IllegalArgumentException("Either Grantee or Permission must be provided"); - } - this.grantee = grantee; - this.permission = permission; - } - - public Grantee grantee() { - return grantee; - } - - public Permission permission() { - return permission; - } - - public String granteeUri() { - return grantee == null ? null : grantee.uri(); - } - - public String granteeId() { - return grantee == null ? null : grantee.id(); - } -} diff --git a/api/src/main/java/io/minio/messages/Grantee.java b/api/src/main/java/io/minio/messages/Grantee.java deleted file mode 100644 index 42b17107d..000000000 --- a/api/src/main/java/io/minio/messages/Grantee.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Attribute; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Namespace; -import org.simpleframework.xml.Root; - -/** Helper class to denote for the person being granted permissions of {@link Grant}. */ -@Root(name = "Grantee") -@Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class Grantee { - @Attribute(name = "type") - private String xsiType; - - @Element(name = "DisplayName", required = false) - private String displayName; - - @Element(name = "EmailAddress", required = false) - private String emailAddress; - - @Element(name = "ID", required = false) - private String id; - - @Element(name = "Type") - private GranteeType type; - - @Element(name = "URI", required = false) - private String uri; - - public Grantee( - @Nonnull GranteeType type, - @Nullable String displayName, - @Nullable String emailAddress, - @Nullable String id, - @Nullable String uri) { - this.type = Objects.requireNonNull(type, "Type must not be null"); - this.displayName = displayName; - this.emailAddress = emailAddress; - this.id = id; - this.uri = uri; - } - - public Grantee( - @Nonnull @Attribute(name = "type") String xsiType, - @Nonnull @Element(name = "Type") GranteeType type, - @Nullable @Element(name = "DisplayName", required = false) String displayName, - @Nullable @Element(name = "EmailAddress", required = false) String emailAddress, - @Nullable @Element(name = "ID", required = false) String id, - @Nullable @Element(name = "URI", required = false) String uri) { - this(type, displayName, emailAddress, id, uri); - this.xsiType = xsiType; - } - - public String displayName() { - return displayName; - } - - public String emailAddress() { - return emailAddress; - } - - public String id() { - return id; - } - - public GranteeType type() { - return type; - } - - public String uri() { - return uri; - } -} diff --git a/api/src/main/java/io/minio/messages/GranteeType.java b/api/src/main/java/io/minio/messages/GranteeType.java deleted file mode 100644 index 74311e2ea..000000000 --- a/api/src/main/java/io/minio/messages/GranteeType.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; -import org.simpleframework.xml.convert.Converter; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.OutputNode; - -/** GranteeType represents type of grantee. */ -@Root(name = "Type") -@Convert(GranteeType.GranteeTypeConverter.class) -public enum GranteeType { - CANONICAL_USER("CanonicalUser"), - AMAZON_CUSTOMER_BY_EMAIL("AmazonCustomerByEmail"), - GROUP("Group"); - - private final String value; - - private GranteeType(String value) { - this.value = value; - } - - public String toString() { - return this.value; - } - - /** Returns GranteeType of given string. */ - public static GranteeType fromString(String granteeTypeString) { - for (GranteeType granteeType : GranteeType.values()) { - if (granteeTypeString.equals(granteeType.value)) { - return granteeType; - } - } - - throw new IllegalArgumentException("Unknown grantee type '" + granteeTypeString + "'"); - } - - /** XML converter class. */ - public static class GranteeTypeConverter implements Converter { - @Override - public GranteeType read(InputNode node) throws Exception { - return GranteeType.fromString(node.getValue()); - } - - @Override - public void write(OutputNode node, GranteeType granteeType) throws Exception { - node.setValue(granteeType.toString()); - } - } -} diff --git a/api/src/main/java/io/minio/messages/Identity.java b/api/src/main/java/io/minio/messages/Identity.java deleted file mode 100644 index 615f47343..000000000 --- a/api/src/main/java/io/minio/messages/Identity.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2020 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** Helper class to denote user or owner identity for {@link Event} and {@link BucketMetadata}. */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = "UwF", - justification = "Everything in this class is initialized by JSON unmarshalling.") -public class Identity { - @JsonProperty private String principalId; - - public String principalId() { - return principalId; - } -} diff --git a/api/src/main/java/io/minio/messages/InitiateMultipartUploadResult.java b/api/src/main/java/io/minio/messages/InitiateMultipartUploadResult.java index b8a3c1519..d8470cef3 100644 --- a/api/src/main/java/io/minio/messages/InitiateMultipartUploadResult.java +++ b/api/src/main/java/io/minio/messages/InitiateMultipartUploadResult.java @@ -16,12 +16,13 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of response XML of CreateMultipartUpload * API. */ @@ -53,4 +54,11 @@ public String objectName() { public String uploadId() { return uploadId; } + + @Override + public String toString() { + return String.format( + "InitiateMultipartUploadResult{bucketName=%s, objectName=%s, uploadId=%s}", + Utils.stringify(bucketName), Utils.stringify(objectName), Utils.stringify(uploadId)); + } } diff --git a/api/src/main/java/io/minio/messages/Initiator.java b/api/src/main/java/io/minio/messages/Initiator.java index 84091c91b..809937f49 100644 --- a/api/src/main/java/io/minio/messages/Initiator.java +++ b/api/src/main/java/io/minio/messages/Initiator.java @@ -16,13 +16,11 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; -/** - * Helper class to denote Initator information of a multipart upload and used in {@link - * ListMultipartUploadsResult} and {@link ListPartsResult}. - */ +/** Initiator information of {@link ListMultipartUploadsResult} and {@link ListPartsResult}. */ @Root(name = "Initiator", strict = false) public class Initiator { @Element(name = "ID", required = false) @@ -42,4 +40,10 @@ public String id() { public String displayName() { return displayName; } + + @Override + public String toString() { + return String.format( + "Initiator{id=%s, displayName=%s}", Utils.stringify(id), Utils.stringify(displayName)); + } } diff --git a/api/src/main/java/io/minio/messages/InputSerialization.java b/api/src/main/java/io/minio/messages/InputSerialization.java index a0e4e9003..c2e6a9a69 100644 --- a/api/src/main/java/io/minio/messages/InputSerialization.java +++ b/api/src/main/java/io/minio/messages/InputSerialization.java @@ -19,7 +19,7 @@ import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; -/** Helper class to denote Input Serialization information of {@link SelectObjectContentRequest}. */ +/** Input serialization information of {@link SelectObjectContentRequest}. */ @Root(name = "InputSerialization") @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public class InputSerialization { @@ -27,16 +27,23 @@ public class InputSerialization { private CompressionType compressionType; @Element(name = "CSV", required = false) - private CsvInputSerialization csv; + private CSV csv; @Element(name = "JSON", required = false) - private JsonInputSerialization json; + private JSON json; @Element(name = "Parquet", required = false) - private ParquetInputSerialization parquet; + private Parquet parquet; + + private InputSerialization(CompressionType compressionType, CSV csv, JSON json, Parquet parquet) { + this.compressionType = compressionType; + this.csv = csv; + this.json = json; + this.parquet = parquet; + } /** Constructs a new InputSerialization object with CSV. */ - public InputSerialization( + public static InputSerialization newCSV( CompressionType compressionType, boolean allowQuotedRecordDelimiter, Character comments, @@ -45,26 +52,106 @@ public InputSerialization( Character quoteCharacter, Character quoteEscapeCharacter, Character recordDelimiter) { - this.compressionType = compressionType; - this.csv = - new CsvInputSerialization( + return new InputSerialization( + compressionType, + new CSV( allowQuotedRecordDelimiter, comments, fieldDelimiter, fileHeaderInfo, quoteCharacter, quoteEscapeCharacter, - recordDelimiter); + recordDelimiter), + null, + null); } /** Constructs a new InputSerialization object with JSON. */ - public InputSerialization(CompressionType compressionType, JsonType type) { - this.compressionType = compressionType; - this.json = new JsonInputSerialization(type); + public static InputSerialization newJSON(CompressionType compressionType, JsonType type) { + return new InputSerialization(compressionType, null, new JSON(type), null); } /** Constructs a new InputSerialization object with Parquet. */ - public InputSerialization() { - this.parquet = new ParquetInputSerialization(); + public static InputSerialization newParquet() { + return new InputSerialization(null, null, null, new Parquet()); + } + + /** CSV input serialization information of {@link InputSerialization}. */ + @Root(name = "CSV") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class CSV { + @Element(name = "AllowQuotedRecordDelimiter", required = false) + private boolean allowQuotedRecordDelimiter; + + @Element(name = "Comments", required = false) + private Character comments; + + @Element(name = "FieldDelimiter", required = false) + private Character fieldDelimiter; + + @Element(name = "FileHeaderInfo", required = false) + private FileHeaderInfo fileHeaderInfo; + + @Element(name = "QuoteCharacter", required = false) + private Character quoteCharacter; + + @Element(name = "QuoteEscapeCharacter", required = false) + private Character quoteEscapeCharacter; + + @Element(name = "RecordDelimiter", required = false) + private Character recordDelimiter; + + public CSV( + boolean allowQuotedRecordDelimiter, + Character comments, + Character fieldDelimiter, + FileHeaderInfo fileHeaderInfo, + Character quoteCharacter, + Character quoteEscapeCharacter, + Character recordDelimiter) { + this.allowQuotedRecordDelimiter = allowQuotedRecordDelimiter; + this.comments = comments; + this.fieldDelimiter = fieldDelimiter; + this.fileHeaderInfo = fileHeaderInfo; + this.quoteCharacter = quoteCharacter; + this.quoteEscapeCharacter = quoteEscapeCharacter; + this.recordDelimiter = recordDelimiter; + } + } + + /** JSON input serialization information of {@link InputSerialization}. */ + @Root(name = "JSON") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class JSON { + @Element(name = "Type", required = false) + private JsonType type; + + public JSON(JsonType type) { + this.type = type; + } + } + + /** Parquet input serialization information of {@link InputSerialization}. */ + @Root(name = "Parquet") + public static class Parquet {} + + /** Compression format of CSV and JSON input serialization. */ + public enum CompressionType { + NONE, + GZIP, + BZIP2; + } + + /** First line description of CSV object. */ + public enum FileHeaderInfo { + USE, + IGNORE, + NONE; + } + + /** JSON object type of {@link JSON}. */ + public enum JsonType { + DOCUMENT, + LINES; } } diff --git a/api/src/main/java/io/minio/messages/Item.java b/api/src/main/java/io/minio/messages/Item.java index e13573cd6..2a6547925 100644 --- a/api/src/main/java/io/minio/messages/Item.java +++ b/api/src/main/java/io/minio/messages/Item.java @@ -16,17 +16,25 @@ package io.minio.messages; +import io.minio.Time; import io.minio.Utils; import java.time.ZonedDateTime; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import javax.annotation.Nonnull; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; +import org.simpleframework.xml.convert.Converter; +import org.simpleframework.xml.stream.InputNode; +import org.simpleframework.xml.stream.OutputNode; /** - * Helper class to denote Object information in {@link ListBucketResultV1}, {@link - * ListBucketResultV2} and {@link ListVersionsResult}. + * Object information in {@link ListBucketResultV1}, {@link ListBucketResultV2} and {@link + * ListVersionsResult}. */ public abstract class Item { @Element(name = "ETag", required = false) @@ -36,7 +44,7 @@ public abstract class Item { private String objectName; @Element(name = "LastModified") - private ResponseDate lastModified; + private Time.S3Time lastModified; @Element(name = "Owner", required = false) private Owner owner; @@ -54,7 +62,7 @@ public abstract class Item { private String versionId; // except ListObjects V1 @Element(name = "UserMetadata", required = false) - private Metadata userMetadata; + private UserMetadata userMetadata; @Element(name = "UserTags", required = false) private String userTags; @@ -90,7 +98,7 @@ public String objectName() { /** Returns last modified time of the object. */ public ZonedDateTime lastModified() { - return (lastModified == null) ? null : lastModified.zonedDateTime(); + return lastModified == null ? null : lastModified.toZonedDateTime(); } /** Returns ETag of the object. */ @@ -139,7 +147,7 @@ public boolean isDir() { /** Returns whether this item is a delete marker or not. */ public boolean isDeleteMarker() { - return this instanceof DeleteMarker; + return this instanceof ListVersionsResult.DeleteMarker; } public List checksumAlgorithm() { @@ -154,17 +162,41 @@ public RestoreStatus restoreStatus() { return restoreStatus; } + @Override + public String toString() { + return String.format( + "etag=%s, objectName=%s, lastModified=%s, owner=%s, size=%s, storageClass=%s, isLatest=%s, " + + "versionId=%s, userMetadata=%s, userTags=%s, checksumAlgorithm=%s, checksumType=%s, " + + "restoreStatus=%s, isDir=%s, encodingType=%s", + Utils.stringify(etag), + Utils.stringify(objectName), + Utils.stringify(lastModified), + Utils.stringify(owner), + Utils.stringify(size), + Utils.stringify(storageClass), + Utils.stringify(isLatest), + Utils.stringify(versionId), + Utils.stringify(userMetadata), + Utils.stringify(userTags), + Utils.stringify(checksumAlgorithm), + Utils.stringify(checksumType), + Utils.stringify(restoreStatus), + Utils.stringify(isDir), + Utils.stringify(encodingType)); + } + + /** Restore status of object information. */ @Root(name = "RestoreStatus", strict = false) public static class RestoreStatus { @Element(name = "IsRestoreInProgress", required = false) private Boolean isRestoreInProgress; @Element(name = "RestoreExpiryDate", required = false) - private ResponseDate restoreExpiryDate; + private Time.S3Time restoreExpiryDate; public RestoreStatus( @Element(name = "IsRestoreInProgress", required = false) Boolean isRestoreInProgress, - @Element(name = "RestoreExpiryDate", required = false) ResponseDate restoreExpiryDate) { + @Element(name = "RestoreExpiryDate", required = false) Time.S3Time restoreExpiryDate) { this.isRestoreInProgress = isRestoreInProgress; this.restoreExpiryDate = restoreExpiryDate; } @@ -174,7 +206,69 @@ public Boolean isRestoreInProgress() { } public ZonedDateTime restoreExpiryDate() { - return restoreExpiryDate == null ? null : restoreExpiryDate.zonedDateTime(); + return restoreExpiryDate == null ? null : restoreExpiryDate.toZonedDateTime(); + } + + @Override + public String toString() { + return String.format( + "RestoreStatus{isRestoreInProgress=%s, restoreExpiryDate=%s}", + Utils.stringify(isRestoreInProgress), Utils.stringify(restoreExpiryDate)); + } + } + + /** User metadata of object information. */ + @Root(name = "UserMetadata") + @Convert(UserMetadata.UserMetadataConverter.class) + public static class UserMetadata { + Map map; + + public UserMetadata() {} + + public UserMetadata(@Nonnull Map map) { + this.map = + Utils.unmodifiableMap(Objects.requireNonNull(map, "User metadata must not be null")); + } + + public Map get() { + return map; + } + + @Override + public String toString() { + return String.format("UserMetadata{%s}", Utils.stringify(map)); + } + + /** XML converter user metadata of object information. */ + public static class UserMetadataConverter implements Converter { + @Override + public UserMetadata read(InputNode node) throws Exception { + Map map = new HashMap<>(); + while (true) { + InputNode childNode = node.getNext(); + if (childNode == null) { + break; + } + + map.put(childNode.getName(), childNode.getValue()); + } + + if (map.size() > 0) { + return new UserMetadata(map); + } + + return null; + } + + @Override + public void write(OutputNode node, UserMetadata metadata) throws Exception { + for (Map.Entry entry : metadata.get().entrySet()) { + OutputNode childNode = node.getChild(entry.getKey()); + childNode.setValue(entry.getValue()); + } + + node.commit(); + } } } } diff --git a/api/src/main/java/io/minio/messages/JsonInputSerialization.java b/api/src/main/java/io/minio/messages/JsonInputSerialization.java deleted file mode 100644 index 21e7b52dd..000000000 --- a/api/src/main/java/io/minio/messages/JsonInputSerialization.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote JSON input serialization request XML as per {@link - * SelectObjectContentRequest}. - */ -@Root(name = "JSON") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class JsonInputSerialization { - @Element(name = "Type", required = false) - private JsonType type; - - /** Constructs a new JsonInputSerialization object. */ - public JsonInputSerialization(JsonType type) { - this.type = type; - } -} diff --git a/api/src/main/java/io/minio/messages/JsonOutputSerialization.java b/api/src/main/java/io/minio/messages/JsonOutputSerialization.java deleted file mode 100644 index 5fbc2b294..000000000 --- a/api/src/main/java/io/minio/messages/JsonOutputSerialization.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote JSON output serialization request XML as per {@link - * SelectObjectContentRequest}. - */ -@Root(name = "JSON") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class JsonOutputSerialization { - @Element(name = "RecordDelimiter", required = false) - private Character recordDelimiter; - - /** Constructs a new JsonOutputSerialization object. */ - public JsonOutputSerialization(Character recordDelimiter) { - this.recordDelimiter = recordDelimiter; - } -} diff --git a/api/src/main/java/io/minio/messages/JsonType.java b/api/src/main/java/io/minio/messages/JsonType.java deleted file mode 100644 index d1e79865e..000000000 --- a/api/src/main/java/io/minio/messages/JsonType.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -/** The type of JSON. */ -public enum JsonType { - DOCUMENT, - LINES; -} diff --git a/api/src/main/java/io/minio/messages/LegalHold.java b/api/src/main/java/io/minio/messages/LegalHold.java index 913c8e213..6af65684d 100644 --- a/api/src/main/java/io/minio/messages/LegalHold.java +++ b/api/src/main/java/io/minio/messages/LegalHold.java @@ -16,12 +16,13 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutObjectLegalHold * API and response XML of GetObjectLegalHold @@ -48,4 +49,9 @@ public LegalHold(boolean status) { public boolean status() { return status != null && status.equals("ON"); } + + @Override + public String toString() { + return String.format("LegalHold{status=%s}", Utils.stringify(status)); + } } diff --git a/api/src/main/java/io/minio/messages/LifecycleConfiguration.java b/api/src/main/java/io/minio/messages/LifecycleConfiguration.java index 72659cb0f..bf35ec095 100644 --- a/api/src/main/java/io/minio/messages/LifecycleConfiguration.java +++ b/api/src/main/java/io/minio/messages/LifecycleConfiguration.java @@ -16,16 +16,20 @@ package io.minio.messages; +import io.minio.Time; import io.minio.Utils; +import java.time.ZonedDateTime; import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutBucketLifecycleConfiguration * API and response XML of GetBucketLifecycleConfiguration @@ -35,18 +39,366 @@ @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") public class LifecycleConfiguration { @ElementList(name = "Rule", inline = true) - private List rules; + private List rules; /** Constructs new lifecycle configuration. */ public LifecycleConfiguration( - @Nonnull @ElementList(name = "Rule", inline = true) List rules) { - this.rules = Utils.unmodifiableList(Objects.requireNonNull(rules, "Rules must not be null")); - if (rules.isEmpty()) { + @Nonnull @ElementList(name = "Rule", inline = true) List rules) { + if (Objects.requireNonNull(rules, "Rules must not be null").isEmpty()) { throw new IllegalArgumentException("Rules must not be empty"); } + this.rules = Utils.unmodifiableList(rules); } - public List rules() { + public List rules() { return rules; } + + @Override + public String toString() { + return String.format("LifecycleConfiguration{rules=%s}", Utils.stringify(rules)); + } + + /** Lifecycle rule information of {@link LifecycleConfiguration}. */ + @Root(name = "Rule") + public static class Rule { + @Element(name = "AbortIncompleteMultipartUpload", required = false) + private AbortIncompleteMultipartUpload abortIncompleteMultipartUpload; + + @Element(name = "Expiration", required = false) + private Expiration expiration; + + @Element(name = "Filter", required = false) + private Filter filter; + + @Element(name = "ID", required = false) + private String id; + + @Element(name = "NoncurrentVersionExpiration", required = false) + private NoncurrentVersionExpiration noncurrentVersionExpiration; + + @Element(name = "NoncurrentVersionTransition", required = false) + private NoncurrentVersionTransition noncurrentVersionTransition; + + @Element(name = "Status") + private Status status; + + @Element(name = "Transition", required = false) + private Transition transition; + + /** Constructs new server-side encryption configuration rule. */ + public Rule( + @Nonnull @Element(name = "Status") Status status, + @Nullable @Element(name = "AbortIncompleteMultipartUpload", required = false) + AbortIncompleteMultipartUpload abortIncompleteMultipartUpload, + @Nullable @Element(name = "Expiration", required = false) Expiration expiration, + @Nonnull @Element(name = "Filter", required = false) Filter filter, + @Nullable @Element(name = "ID", required = false) String id, + @Nullable @Element(name = "NoncurrentVersionExpiration", required = false) + NoncurrentVersionExpiration noncurrentVersionExpiration, + @Nullable @Element(name = "NoncurrentVersionTransition", required = false) + NoncurrentVersionTransition noncurrentVersionTransition, + @Nullable @Element(name = "Transition", required = false) Transition transition) { + if (abortIncompleteMultipartUpload == null + && expiration == null + && noncurrentVersionExpiration == null + && noncurrentVersionTransition == null + && transition == null) { + throw new IllegalArgumentException( + "At least one of action (AbortIncompleteMultipartUpload, Expiration, " + + "NoncurrentVersionExpiration, NoncurrentVersionTransition or Transition) must be " + + "specified in a rule"); + } + + if (id != null) { + id = id.trim(); + if (id.isEmpty()) throw new IllegalArgumentException("ID must be non-empty string"); + if (id.length() > 255) + throw new IllegalArgumentException("ID must not exceed 255 characters"); + } + + this.abortIncompleteMultipartUpload = abortIncompleteMultipartUpload; + this.expiration = expiration; + this.filter = Objects.requireNonNull(filter, "Filter must not be null"); + this.id = id; + this.noncurrentVersionExpiration = noncurrentVersionExpiration; + this.noncurrentVersionTransition = noncurrentVersionTransition; + this.status = Objects.requireNonNull(status, "Status must not be null"); + this.transition = transition; + } + + public AbortIncompleteMultipartUpload abortIncompleteMultipartUpload() { + return abortIncompleteMultipartUpload; + } + + public Expiration expiration() { + return expiration; + } + + public Filter filter() { + return this.filter; + } + + public String id() { + return this.id; + } + + public NoncurrentVersionExpiration noncurrentVersionExpiration() { + return noncurrentVersionExpiration; + } + + public NoncurrentVersionTransition noncurrentVersionTransition() { + return noncurrentVersionTransition; + } + + public Status status() { + return this.status; + } + + public Transition transition() { + return transition; + } + + @Override + public String toString() { + return String.format( + "Rule{abortIncompleteMultipartUpload=%s, expiration=%s, filter=%s, id=%s," + + " noncurrentVersionExpiration=%s, noncurrentVersionTransition=%s, status=%s," + + " transition=%s}", + Utils.stringify(abortIncompleteMultipartUpload), + Utils.stringify(expiration), + Utils.stringify(filter), + Utils.stringify(id), + Utils.stringify(noncurrentVersionExpiration), + Utils.stringify(noncurrentVersionTransition), + Utils.stringify(status), + Utils.stringify(transition)); + } + } + + /** Abort incomplete multipart upload information of {@link LifecycleConfiguration.Rule}. */ + @Root(name = "AbortIncompleteMultipartUpload") + public static class AbortIncompleteMultipartUpload { + @Element(name = "DaysAfterInitiation") + private int daysAfterInitiation; + + public AbortIncompleteMultipartUpload( + @Element(name = "DaysAfterInitiation") int daysAfterInitiation) { + this.daysAfterInitiation = daysAfterInitiation; + } + + public int daysAfterInitiation() { + return daysAfterInitiation; + } + + @Override + public String toString() { + return String.format( + "AbortIncompleteMultipartUpload{daysAfterInitiation=%d}", daysAfterInitiation); + } + } + + /** + * Date and days information of {@link LifecycleConfiguration.Expiration} and {@link + * LifecycleConfiguration.Transition}. + */ + public abstract static class DateDays { + @Element(name = "Date", required = false) + protected Time.S3Time date; + + @Element(name = "Days", required = false) + protected Integer days; + + public ZonedDateTime date() { + return date == null ? null : date.toZonedDateTime(); + } + + public Integer days() { + return days; + } + + @Override + public String toString() { + return String.format("date=%s, days=%s", Utils.stringify(date), Utils.stringify(days)); + } + } + + /** Expiration information of {@link LifecycleConfiguration.Rule}. */ + @Root(name = "Expiration") + public static class Expiration extends DateDays { + @Element(name = "ExpiredObjectDeleteMarker", required = false) + private Boolean expiredObjectDeleteMarker; + + @Element(name = "ExpiredObjectAllVersions", required = false) + private Boolean expiredObjectAllVersions; // This is MinIO specific extension. + + public Expiration( + @Nullable @Element(name = "Date", required = false) Time.S3Time date, + @Nullable @Element(name = "Days", required = false) Integer days, + @Nullable @Element(name = "ExpiredObjectDeleteMarker", required = false) + Boolean expiredObjectDeleteMarker) { + if (expiredObjectDeleteMarker != null) { + if (date != null || days != null) { + throw new IllegalArgumentException( + "ExpiredObjectDeleteMarker must not be provided along with Date and Days"); + } + } else if (date != null ^ days != null) { + this.date = date; + this.days = days; + } else { + throw new IllegalArgumentException("Only one of date or days must be set"); + } + + this.expiredObjectDeleteMarker = expiredObjectDeleteMarker; + } + + public Expiration(ZonedDateTime date, Integer days, Boolean expiredObjectDeleteMarker) { + this(date == null ? null : new Time.S3Time(date), days, expiredObjectDeleteMarker); + } + + public Expiration( + @Nullable @Element(name = "Date", required = false) Time.S3Time date, + @Nullable @Element(name = "Days", required = false) Integer days, + @Nullable @Element(name = "ExpiredObjectDeleteMarker", required = false) + Boolean expiredObjectDeleteMarker, + @Element(name = "ExpiredObjectAllVersions", required = false) + Boolean expiredObjectAllVersions) { + this(date, days, expiredObjectDeleteMarker); + this.expiredObjectAllVersions = expiredObjectAllVersions; + } + + public Boolean expiredObjectDeleteMarker() { + return expiredObjectDeleteMarker; + } + + public Boolean expiredObjectAllVersions() { + return expiredObjectAllVersions; + } + + @Override + public String toString() { + return String.format( + "Expiration{%s, expiredObjectDeleteMarker=%s, expiredObjectAllVersions=%s}", + super.toString(), + Utils.stringify(expiredObjectDeleteMarker), + Utils.stringify(expiredObjectAllVersions)); + } + } + + /** Non-current version expiration information of {@link LifecycleConfiguration.Rule}. */ + @Root(name = "NoncurrentVersionExpiration") + public static class NoncurrentVersionExpiration { + @Element(name = "NoncurrentDays") + private int noncurrentDays; + + @Element(name = "NewerNoncurrentVersions", required = false) + private Integer newerNoncurrentVersions; + + public NoncurrentVersionExpiration( + @Element(name = "NoncurrentDays", required = false) int noncurrentDays) { + this.noncurrentDays = noncurrentDays; + } + + public NoncurrentVersionExpiration( + @Element(name = "NoncurrentDays", required = false) int noncurrentDays, + @Element(name = "NewerNoncurrentVersions", required = false) + Integer newerNoncurrentVersions) { + this.noncurrentDays = noncurrentDays; + this.newerNoncurrentVersions = newerNoncurrentVersions; + } + + public int noncurrentDays() { + return noncurrentDays; + } + + public Integer newerNoncurrentVersions() { + return newerNoncurrentVersions; + } + + protected String stringify() { + return String.format( + "noncurrentDays=%d, newerNoncurrentVersions=%s", + noncurrentDays, Utils.stringify(newerNoncurrentVersions)); + } + + @Override + public String toString() { + return String.format("NoncurrentVersionExpiration{%s}", stringify()); + } + } + + /** Non-current version transition information of {@link LifecycleConfiguration.Rule}. */ + @Root(name = "NoncurrentVersionTransition") + public static class NoncurrentVersionTransition extends NoncurrentVersionExpiration { + @Element(name = "StorageClass") + private String storageClass; + + public NoncurrentVersionTransition( + @Element(name = "NoncurrentDays", required = false) int noncurrentDays, + @Nonnull @Element(name = "StorageClass", required = false) String storageClass) { + super(noncurrentDays, null); + if (storageClass == null || storageClass.isEmpty()) { + throw new IllegalArgumentException("StorageClass must be provided"); + } + this.storageClass = storageClass; + } + + public NoncurrentVersionTransition( + @Element(name = "NoncurrentDays", required = false) int noncurrentDays, + @Element(name = "NewerNoncurrentVersions", required = false) + Integer newerNoncurrentVersions, + @Nonnull @Element(name = "StorageClass", required = false) String storageClass) { + super(noncurrentDays, newerNoncurrentVersions); + if (storageClass == null || storageClass.isEmpty()) { + throw new IllegalArgumentException("StorageClass must be provided"); + } + this.storageClass = storageClass; + } + + public String storageClass() { + return storageClass; + } + + @Override + public String toString() { + return String.format( + "NoncurrentVersionTransition{%s, storageClass=%s}", super.stringify(), storageClass); + } + } + + /** Transition information of {@link LifecycleConfiguration.Rule}. */ + @Root(name = "Transition") + public static class Transition extends DateDays { + @Element(name = "StorageClass") + private String storageClass; + + public Transition( + @Nullable @Element(name = "Date", required = false) Time.S3Time date, + @Nullable @Element(name = "Days", required = false) Integer days, + @Nonnull @Element(name = "StorageClass", required = false) String storageClass) { + if (date != null ^ days != null) { + this.date = date; + this.days = days; + } else { + throw new IllegalArgumentException("Only one of date or days must be set"); + } + if (storageClass == null || storageClass.isEmpty()) { + throw new IllegalArgumentException("StorageClass must be provided"); + } + this.storageClass = storageClass; + } + + public Transition(ZonedDateTime date, Integer days, String storageClass) { + this(date == null ? null : new Time.S3Time(date), days, storageClass); + } + + public String storageClass() { + return storageClass; + } + + @Override + public String toString() { + return String.format("Transition{%s, storageClass=%s}", super.toString(), storageClass); + } + } } diff --git a/api/src/main/java/io/minio/messages/LifecycleRule.java b/api/src/main/java/io/minio/messages/LifecycleRule.java deleted file mode 100644 index ab338ca3a..000000000 --- a/api/src/main/java/io/minio/messages/LifecycleRule.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote Rule information for {@link LifecycleConfiguration}. */ -@Root(name = "Rule") -public class LifecycleRule { - @Element(name = "AbortIncompleteMultipartUpload", required = false) - private AbortIncompleteMultipartUpload abortIncompleteMultipartUpload; - - @Element(name = "Expiration", required = false) - private Expiration expiration; - - @Element(name = "Filter", required = false) - private RuleFilter filter; - - @Element(name = "ID", required = false) - private String id; - - @Element(name = "NoncurrentVersionExpiration", required = false) - private NoncurrentVersionExpiration noncurrentVersionExpiration; - - @Element(name = "NoncurrentVersionTransition", required = false) - private NoncurrentVersionTransition noncurrentVersionTransition; - - @Element(name = "Status") - private Status status; - - @Element(name = "Transition", required = false) - private Transition transition; - - /** Constructs new server-side encryption configuration rule. */ - public LifecycleRule( - @Nonnull @Element(name = "Status") Status status, - @Nullable @Element(name = "AbortIncompleteMultipartUpload", required = false) - AbortIncompleteMultipartUpload abortIncompleteMultipartUpload, - @Nullable @Element(name = "Expiration", required = false) Expiration expiration, - @Nonnull @Element(name = "Filter", required = false) RuleFilter filter, - @Nullable @Element(name = "ID", required = false) String id, - @Nullable @Element(name = "NoncurrentVersionExpiration", required = false) - NoncurrentVersionExpiration noncurrentVersionExpiration, - @Nullable @Element(name = "NoncurrentVersionTransition", required = false) - NoncurrentVersionTransition noncurrentVersionTransition, - @Nullable @Element(name = "Transition", required = false) Transition transition) { - if (abortIncompleteMultipartUpload == null - && expiration == null - && noncurrentVersionExpiration == null - && noncurrentVersionTransition == null - && transition == null) { - throw new IllegalArgumentException( - "At least one of action (AbortIncompleteMultipartUpload, Expiration, " - + "NoncurrentVersionExpiration, NoncurrentVersionTransition or Transition) must be " - + "specified in a rule"); - } - - if (id != null) { - id = id.trim(); - if (id.isEmpty()) throw new IllegalArgumentException("ID must be non-empty string"); - if (id.length() > 255) throw new IllegalArgumentException("ID must be exceed 255 characters"); - } - - this.abortIncompleteMultipartUpload = abortIncompleteMultipartUpload; - this.expiration = expiration; - this.filter = Objects.requireNonNull(filter, "Filter must not be null"); - this.id = id; - this.noncurrentVersionExpiration = noncurrentVersionExpiration; - this.noncurrentVersionTransition = noncurrentVersionTransition; - this.status = Objects.requireNonNull(status, "Status must not be null"); - this.transition = transition; - } - - public AbortIncompleteMultipartUpload abortIncompleteMultipartUpload() { - return abortIncompleteMultipartUpload; - } - - public Expiration expiration() { - return expiration; - } - - public RuleFilter filter() { - return this.filter; - } - - public String id() { - return this.id; - } - - public NoncurrentVersionExpiration noncurrentVersionExpiration() { - return noncurrentVersionExpiration; - } - - public NoncurrentVersionTransition noncurrentVersionTransition() { - return noncurrentVersionTransition; - } - - public Status status() { - return this.status; - } - - public Transition transition() { - return transition; - } -} diff --git a/api/src/main/java/io/minio/messages/ListAllMyBucketsResult.java b/api/src/main/java/io/minio/messages/ListAllMyBucketsResult.java index f6909996f..0f739c2b5 100644 --- a/api/src/main/java/io/minio/messages/ListAllMyBucketsResult.java +++ b/api/src/main/java/io/minio/messages/ListAllMyBucketsResult.java @@ -16,7 +16,9 @@ package io.minio.messages; +import io.minio.Time; import io.minio.Utils; +import java.time.ZonedDateTime; import java.util.List; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; @@ -24,7 +26,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of ListBuckets API. */ @Root(name = "ListAllMyBucketsResult", strict = false) @@ -61,4 +63,50 @@ public String prefix() { public String continuationToken() { return continuationToken; } + + @Override + public String toString() { + return String.format( + "ListAllMyBucketsResult{owner=%s, buckets=%s, prefix=%s, continuationToken=%s}", + Utils.stringify(owner), + Utils.stringify(buckets), + Utils.stringify(prefix), + Utils.stringify(continuationToken)); + } + + /** Bucket information of {@link ListAllMyBucketsResult}. */ + @Root(name = "Bucket", strict = false) + public static class Bucket { + @Element(name = "Name") + private String name; + + @Element(name = "CreationDate") + private Time.S3Time creationDate; + + @Element(name = "BucketRegion", required = false) + private String bucketRegion; + + public Bucket() {} + + /** Returns bucket name. */ + public String name() { + return name; + } + + /** Returns creation date. */ + public ZonedDateTime creationDate() { + return creationDate == null ? null : creationDate.toZonedDateTime(); + } + + public String bucketRegion() { + return bucketRegion; + } + + @Override + public String toString() { + return String.format( + "Bucket{name=%s, creationDate=%s, bucketRegion=%s}", + Utils.stringify(name), Utils.stringify(creationDate), Utils.stringify(bucketRegion)); + } + } } diff --git a/api/src/main/java/io/minio/messages/ListBucketResultV1.java b/api/src/main/java/io/minio/messages/ListBucketResultV1.java index a88bde5d8..6fb9cc918 100644 --- a/api/src/main/java/io/minio/messages/ListBucketResultV1.java +++ b/api/src/main/java/io/minio/messages/ListBucketResultV1.java @@ -24,7 +24,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of ListObjects API. */ @Root(name = "ListBucketResult", strict = false) @@ -51,4 +51,14 @@ public String nextMarker() { public List contents() { return Utils.unmodifiableList(contents); } + + @Override + public String toString() { + return String.format( + "ListBucketResultV1{%s, marker=%s, nextMarker=%s, contents=%s}", + super.toString(), + Utils.stringify(marker), + Utils.stringify(nextMarker), + Utils.stringify(contents)); + } } diff --git a/api/src/main/java/io/minio/messages/ListBucketResultV2.java b/api/src/main/java/io/minio/messages/ListBucketResultV2.java index 5d67d1ffd..75b6b4d49 100644 --- a/api/src/main/java/io/minio/messages/ListBucketResultV2.java +++ b/api/src/main/java/io/minio/messages/ListBucketResultV2.java @@ -24,7 +24,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of ListObjectsV2 * API. */ @@ -71,4 +71,17 @@ public String nextContinuationToken() { public List contents() { return Utils.unmodifiableList(contents); } + + @Override + public String toString() { + return String.format( + "ListBucketResultV2{%s, keyCount=%s, startAfter=%s, continuationToken=%s," + + " nextContinuationToken=%s, contents=%s}", + super.toString(), + Utils.stringify(keyCount), + Utils.stringify(startAfter), + Utils.stringify(continuationToken), + Utils.stringify(nextContinuationToken), + Utils.stringify(contents)); + } } diff --git a/api/src/main/java/io/minio/messages/ListMultipartUploadsResult.java b/api/src/main/java/io/minio/messages/ListMultipartUploadsResult.java index 3cecf55f7..84c7912eb 100644 --- a/api/src/main/java/io/minio/messages/ListMultipartUploadsResult.java +++ b/api/src/main/java/io/minio/messages/ListMultipartUploadsResult.java @@ -16,7 +16,9 @@ package io.minio.messages; +import io.minio.Time; import io.minio.Utils; +import java.time.ZonedDateTime; import java.util.List; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; @@ -24,7 +26,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of ListMultipartUploads * API. */ @@ -103,4 +105,123 @@ public String encodingType() { public List uploads() { return Utils.unmodifiableList(uploads); } + + @Override + public String toString() { + return String.format( + "ListMultipartUploadsResult{bucketName=%s, encodingType=%s, keyMarker=%s," + + " uploadIdMarker=%s, nextKeyMarker=%s, nextUploadIdMarker=%s, maxUploads=%s," + + " isTruncated=%s, uploads=%s}", + Utils.stringify(bucketName), + Utils.stringify(encodingType), + Utils.stringify(keyMarker), + Utils.stringify(uploadIdMarker), + Utils.stringify(nextKeyMarker), + Utils.stringify(nextUploadIdMarker), + Utils.stringify(maxUploads), + Utils.stringify(isTruncated), + Utils.stringify(uploads)); + } + + /** Upload information of {@link ListMultipartUploadsResult}. */ + @Root(name = "Upload", strict = false) + @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") + public static class Upload { + @Element(name = "Key") + private String objectName; + + @Element(name = "UploadId") + private String uploadId; + + @Element(name = "Initiator") + private Initiator initiator; + + @Element(name = "Owner") + private Owner owner; + + @Element(name = "StorageClass") + private String storageClass; + + @Element(name = "Initiated") + private Time.S3Time initiated; + + @Element(name = "ChecksumAlgorithm", required = false) + private String checksumAlgorithm; + + @Element(name = "ChecksumType", required = false) + private String checksumType; + + private long aggregatedPartSize; + private String encodingType = null; + + public Upload() {} + + /** Returns object name. */ + public String objectName() { + return Utils.urlDecode(objectName, encodingType); + } + + /** Returns upload ID. */ + public String uploadId() { + return uploadId; + } + + /** Returns initiator information. */ + public Initiator initiator() { + return initiator; + } + + /** Returns owner information. */ + public Owner owner() { + return owner; + } + + /** Returns storage class. */ + public String storageClass() { + return storageClass; + } + + /** Returns initiated time. */ + public ZonedDateTime initiated() { + return initiated == null ? null : initiated.toZonedDateTime(); + } + + /** Returns aggregated part size. */ + public long aggregatedPartSize() { + return aggregatedPartSize; + } + + /** Sets given aggregated part size. */ + public void setAggregatedPartSize(long size) { + this.aggregatedPartSize = size; + } + + public void setEncodingType(String encodingType) { + this.encodingType = encodingType; + } + + public String checksumAlgorithm() { + return checksumAlgorithm; + } + + public String checksumType() { + return checksumType; + } + + @Override + public String toString() { + return String.format( + "Upload{objectName=%s, uploadId=%s, initiator=%s, owner=%s, storageClass=%s, " + + "initiated=%s, checksumAlgorithm=%s, checksumType=%s, aggregatedPartSize=%s}", + Utils.stringify(objectName), + Utils.stringify(uploadId), + Utils.stringify(initiator), + Utils.stringify(owner), + Utils.stringify(storageClass), + Utils.stringify(initiated), + Utils.stringify(checksumAlgorithm), + Utils.stringify(checksumType), + Utils.stringify(aggregatedPartSize)); + } + } } diff --git a/api/src/main/java/io/minio/messages/ListObjectsResult.java b/api/src/main/java/io/minio/messages/ListObjectsResult.java index 235001676..ed085e0ad 100644 --- a/api/src/main/java/io/minio/messages/ListObjectsResult.java +++ b/api/src/main/java/io/minio/messages/ListObjectsResult.java @@ -20,9 +20,10 @@ import java.util.List; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; +import org.simpleframework.xml.Root; /** - * Base class of {@link ListBucketResultV1}, {@link ListBucketResultV2} and {@link + * Base object information of {@link ListBucketResultV1}, {@link ListBucketResultV2} and {@link * ListVersionsResult}. */ public abstract class ListObjectsResult { @@ -47,7 +48,8 @@ public abstract class ListObjectsResult { @ElementList(name = "CommonPrefixes", inline = true, required = false) private List commonPrefixes; - private static final List deleteMarkers = Utils.unmodifiableList(null); + private static final List deleteMarkers = + Utils.unmodifiableList(null); public ListObjectsResult() {} @@ -85,9 +87,41 @@ public List commonPrefixes() { return Utils.unmodifiableList(commonPrefixes); } - public List deleteMarkers() { + public List deleteMarkers() { return deleteMarkers; } public abstract List contents(); + + @Override + public String toString() { + return String.format( + "name=%s, encodingType=%s, prefix=%s, delimiter=%s, isTruncated=%s, maxKeys=%s, commonPrefixes=%s, deleteMarkers=%s", + Utils.stringify(name), + Utils.stringify(encodingType), + Utils.stringify(prefix), + Utils.stringify(delimiter), + Utils.stringify(isTruncated), + Utils.stringify(maxKeys), + Utils.stringify(commonPrefixes), + Utils.stringify(deleteMarkers)); + } + + /** Common prefix informaton. */ + @Root(name = "CommonPrefixes", strict = false) + public static class Prefix { + @Element(name = "Prefix") + private String prefix; + + public Prefix() {} + + public Item toItem() { + return new Contents(prefix); + } + + @Override + public String toString() { + return String.format("Prefix{%s}", Utils.stringify(prefix)); + } + } } diff --git a/api/src/main/java/io/minio/messages/ListPartsResult.java b/api/src/main/java/io/minio/messages/ListPartsResult.java index 9bdd33489..5aa708496 100644 --- a/api/src/main/java/io/minio/messages/ListPartsResult.java +++ b/api/src/main/java/io/minio/messages/ListPartsResult.java @@ -17,19 +17,17 @@ package io.minio.messages; import io.minio.Utils; -import java.util.List; import org.simpleframework.xml.Element; -import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of response XML of ListParts API. */ @Root(name = "ListPartsResult", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class ListPartsResult { +public class ListPartsResult extends BasePartsResult { @Element(name = "Bucket") private String bucketName; @@ -45,21 +43,6 @@ public class ListPartsResult { @Element(name = "StorageClass") private String storageClass; - @Element(name = "PartNumberMarker") - private int partNumberMarker; - - @Element(name = "NextPartNumberMarker") - private int nextPartNumberMarker; - - @Element(name = "MaxParts") - private int maxParts; - - @Element(name = "IsTruncated") - private boolean isTruncated; - - @ElementList(name = "Part", inline = true, required = false) - private List partList; - @Element(name = "UploadId", required = false) private String uploadId; @@ -69,7 +52,9 @@ public class ListPartsResult { @Element(name = "ChecksumType", required = false) private String checksumType; - public ListPartsResult() {} + public ListPartsResult() { + super(); + } /** Returns bucket name. */ public String bucketName() { @@ -86,7 +71,7 @@ public String storageClass() { return storageClass; } - /** Returns initator information. */ + /** Returns initiator information. */ public Initiator initiator() { return initiator; } @@ -96,31 +81,6 @@ public Owner owner() { return owner; } - /** Returns maximum parts information received. */ - public int maxParts() { - return maxParts; - } - - /** Returns whether the result is truncated or not. */ - public boolean isTruncated() { - return isTruncated; - } - - /** Returns part number marker. */ - public int partNumberMarker() { - return partNumberMarker; - } - - /** Returns next part number marker. */ - public int nextPartNumberMarker() { - return nextPartNumberMarker; - } - - /** Returns List of Part. */ - public List partList() { - return Utils.unmodifiableList(partList); - } - public String uploadId() { return uploadId; } @@ -132,4 +92,20 @@ public String checksumAlgorithm() { public String checksumType() { return checksumType; } + + @Override + public String toString() { + return String.format( + "ListPartsResult{bucketName=%s, objectName=%s, initiator=%s, owner=%s, storageClass=%s," + + " uploadId=%s, checksumAlgorithm=%s, checksumType=%s, %s}", + Utils.stringify(bucketName), + Utils.stringify(objectName), + Utils.stringify(initiator), + Utils.stringify(owner), + Utils.stringify(storageClass), + Utils.stringify(uploadId), + Utils.stringify(checksumAlgorithm), + Utils.stringify(checksumType), + super.toString()); + } } diff --git a/api/src/main/java/io/minio/messages/ListVersionsResult.java b/api/src/main/java/io/minio/messages/ListVersionsResult.java index 13e22f522..c9e85c0a3 100644 --- a/api/src/main/java/io/minio/messages/ListVersionsResult.java +++ b/api/src/main/java/io/minio/messages/ListVersionsResult.java @@ -24,7 +24,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of response XML of ListObjectVersions * API. */ @@ -74,4 +74,52 @@ public List contents() { public List deleteMarkers() { return Utils.unmodifiableList(deleteMarkers); } + + @Override + public String toString() { + return String.format( + "ListVersionsResult{%s, keyMarker=%s, nextKeyMarker=%s, versionIdMarker=%s," + + " nextVersionIdMarker=%s, contents=%s, deleteMarkers=%s}", + super.toString(), + Utils.stringify(keyMarker), + Utils.stringify(nextKeyMarker), + Utils.stringify(versionIdMarker), + Utils.stringify(nextVersionIdMarker), + Utils.stringify(contents), + Utils.stringify(deleteMarkers)); + } + + /** Object with version information. */ + @Root(name = "Version", strict = false) + public static class Version extends Item { + public Version() { + super(); + } + + public Version(String prefix) { + super(prefix); + } + + @Override + public String toString() { + return String.format("Version{%s}", super.toString()); + } + } + + /** Delete marker information. */ + @Root(name = "DeleteMarker", strict = false) + public static class DeleteMarker extends Item { + public DeleteMarker() { + super(); + } + + public DeleteMarker(String prefix) { + super(prefix); + } + + @Override + public String toString() { + return String.format("DeleteMarker{%s}", super.toString()); + } + } } diff --git a/api/src/main/java/io/minio/messages/LocationConstraint.java b/api/src/main/java/io/minio/messages/LocationConstraint.java index d7c249cea..220203e06 100644 --- a/api/src/main/java/io/minio/messages/LocationConstraint.java +++ b/api/src/main/java/io/minio/messages/LocationConstraint.java @@ -16,12 +16,13 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; import org.simpleframework.xml.Text; /** - * Object representation of response XML of GetBucketLocation * API. */ @@ -36,4 +37,9 @@ public LocationConstraint() {} public String location() { return location; } + + @Override + public String toString() { + return String.format("LocationConstraint{location=%s}", Utils.stringify(location)); + } } diff --git a/api/src/main/java/io/minio/messages/Metadata.java b/api/src/main/java/io/minio/messages/Metadata.java deleted file mode 100644 index 5dab1aaff..000000000 --- a/api/src/main/java/io/minio/messages/Metadata.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import io.minio.Utils; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; -import org.simpleframework.xml.convert.Converter; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.OutputNode; - -/** XML friendly map denotes metadata. */ -@Root(name = "Metadata") -@Convert(Metadata.MetadataConverter.class) -public class Metadata { - Map map; - - public Metadata() {} - - public Metadata(@Nonnull Map map) { - this.map = Utils.unmodifiableMap(Objects.requireNonNull(map, "Metadata must not be null")); - } - - public Map get() { - return map; - } - - /** XML converter class. */ - public static class MetadataConverter implements Converter { - @Override - public Metadata read(InputNode node) throws Exception { - Map map = new HashMap<>(); - while (true) { - InputNode childNode = node.getNext(); - if (childNode == null) { - break; - } - - map.put(childNode.getName(), childNode.getValue()); - } - - if (map.size() > 0) { - return new Metadata(map); - } - - return null; - } - - @Override - public void write(OutputNode node, Metadata metadata) throws Exception { - for (Map.Entry entry : metadata.get().entrySet()) { - OutputNode childNode = node.getChild(entry.getKey()); - childNode.setValue(entry.getValue()); - } - - node.commit(); - } - } -} diff --git a/api/src/main/java/io/minio/messages/Metrics.java b/api/src/main/java/io/minio/messages/Metrics.java deleted file mode 100644 index af5386322..000000000 --- a/api/src/main/java/io/minio/messages/Metrics.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote metrics information for {@link ReplicationDestination}. */ -@Root(name = "Metrics") -public class Metrics { - @Element(name = "EventThreshold") - private ReplicationTimeValue eventThreshold; - - @Element(name = "Status") - private Status status; - - public Metrics( - @Nonnull @Element(name = "EventThreshold") ReplicationTimeValue eventThreshold, - @Nonnull @Element(name = "Status") Status status) { - this.eventThreshold = - Objects.requireNonNull(eventThreshold, "Event threshold must not be null"); - this.status = Objects.requireNonNull(status, "Status must not be null"); - } - - public ReplicationTimeValue eventThreshold() { - return this.eventThreshold; - } - - public Status status() { - return this.status; - } -} diff --git a/api/src/main/java/io/minio/messages/NoncurrentVersionExpiration.java b/api/src/main/java/io/minio/messages/NoncurrentVersionExpiration.java deleted file mode 100644 index b4b66bac0..000000000 --- a/api/src/main/java/io/minio/messages/NoncurrentVersionExpiration.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote noncurrent version expiration information for {@link LifecycleRule}. */ -@Root(name = "NoncurrentVersionExpiration") -public class NoncurrentVersionExpiration { - @Element(name = "NoncurrentDays") - private int noncurrentDays; - - @Element(name = "NewerNoncurrentVersions", required = false) - private Integer newerNoncurrentVersions; - - public NoncurrentVersionExpiration( - @Element(name = "NoncurrentDays", required = false) int noncurrentDays) { - this.noncurrentDays = noncurrentDays; - } - - public NoncurrentVersionExpiration( - @Element(name = "NoncurrentDays", required = false) int noncurrentDays, - @Element(name = "NewerNoncurrentVersions", required = false) - Integer newerNoncurrentVersions) { - this.noncurrentDays = noncurrentDays; - this.newerNoncurrentVersions = newerNoncurrentVersions; - } - - public int noncurrentDays() { - return noncurrentDays; - } - - public Integer newerNoncurrentVersions() { - return newerNoncurrentVersions; - } -} diff --git a/api/src/main/java/io/minio/messages/NoncurrentVersionTransition.java b/api/src/main/java/io/minio/messages/NoncurrentVersionTransition.java deleted file mode 100644 index ddabe5c14..000000000 --- a/api/src/main/java/io/minio/messages/NoncurrentVersionTransition.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote noncurrent version transition information for {@link LifecycleRule}. */ -@Root(name = "NoncurrentVersionTransition") -public class NoncurrentVersionTransition extends NoncurrentVersionExpiration { - @Element(name = "StorageClass") - private String storageClass; - - public NoncurrentVersionTransition( - @Element(name = "NoncurrentDays", required = false) int noncurrentDays, - @Nonnull @Element(name = "StorageClass", required = false) String storageClass) { - super(noncurrentDays, null); - if (storageClass == null || storageClass.isEmpty()) { - throw new IllegalArgumentException("StorageClass must be provided"); - } - this.storageClass = storageClass; - } - - public NoncurrentVersionTransition( - @Element(name = "NoncurrentDays", required = false) int noncurrentDays, - @Element(name = "NewerNoncurrentVersions", required = false) Integer newerNoncurrentVersions, - @Nonnull @Element(name = "StorageClass", required = false) String storageClass) { - super(noncurrentDays, newerNoncurrentVersions); - if (storageClass == null || storageClass.isEmpty()) { - throw new IllegalArgumentException("StorageClass must be provided"); - } - this.storageClass = storageClass; - } - - public String storageClass() { - return storageClass; - } -} diff --git a/api/src/main/java/io/minio/messages/NotificationCommonConfiguration.java b/api/src/main/java/io/minio/messages/NotificationCommonConfiguration.java deleted file mode 100644 index 77c70fffe..000000000 --- a/api/src/main/java/io/minio/messages/NotificationCommonConfiguration.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import io.minio.Utils; -import java.util.List; -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.ElementList; - -/** - * Helper class to denote common fields of {@link CloudFunctionConfiguration}, {@link - * QueueConfiguration} and {@link TopicConfiguration}. - */ -public abstract class NotificationCommonConfiguration { - @Element(name = "Id", required = false) - private String id; - - @ElementList(name = "Event", inline = true) - private List events; - - @Element(name = "Filter", required = false) - private Filter filter; - - public NotificationCommonConfiguration() {} - - /** Returns id. */ - public String id() { - return id; - } - - /** Sets id. */ - public void setId(String id) { - this.id = id; - } - - /** Returns events. */ - public List events() { - return Utils.unmodifiableList(events); - } - - /** Sets event. */ - public void setEvents(@Nonnull List events) { - this.events = Utils.unmodifiableList(Objects.requireNonNull(events, "Events must not be null")); - } - - /** sets filter prefix rule. */ - public void setPrefixRule(String value) throws IllegalArgumentException { - if (filter == null) { - filter = new Filter(); - } - - filter.setPrefixRule(value); - } - - /** sets filter suffix rule. */ - public void setSuffixRule(String value) throws IllegalArgumentException { - if (filter == null) { - filter = new Filter(); - } - - filter.setSuffixRule(value); - } - - /** returns filter rule list. */ - public List filterRuleList() { - return Utils.unmodifiableList(filter == null ? null : filter.filterRuleList()); - } -} diff --git a/api/src/main/java/io/minio/messages/NotificationConfiguration.java b/api/src/main/java/io/minio/messages/NotificationConfiguration.java index ad43defdb..be3518944 100644 --- a/api/src/main/java/io/minio/messages/NotificationConfiguration.java +++ b/api/src/main/java/io/minio/messages/NotificationConfiguration.java @@ -17,14 +17,18 @@ package io.minio.messages; import io.minio.Utils; +import java.util.LinkedList; import java.util.List; +import java.util.Objects; +import javax.annotation.Nonnull; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; +import org.simpleframework.xml.Path; import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutBucketNotificationConfiguration * API and response XML of GetBucketNotificationConfiguration @@ -34,63 +38,281 @@ @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") public class NotificationConfiguration { @ElementList(name = "CloudFunctionConfiguration", inline = true, required = false) - private List cloudFunctionConfigurationList; + private List cloudFunctionConfigurations; @ElementList(name = "QueueConfiguration", inline = true, required = false) - private List queueConfigurationList; + private List queueConfigurations; @ElementList(name = "TopicConfiguration", inline = true, required = false) - private List topicConfigurationList; + private List topicConfigurations; @Element(name = "EventBridgeConfiguration", required = false) private EventBridgeConfiguration eventBridgeConfiguration; - public NotificationConfiguration() {} + private NotificationConfiguration() {} - /** Returns cloud function configuration. */ - public List cloudFunctionConfigurationList() { - return Utils.unmodifiableList(cloudFunctionConfigurationList); + public NotificationConfiguration( + @ElementList(name = "CloudFunctionConfiguration", inline = true, required = false) + List cloudFunctionConfigurations, + @ElementList(name = "QueueConfiguration", inline = true, required = false) + List queueConfigurations, + @ElementList(name = "TopicConfiguration", inline = true, required = false) + List topicConfigurations, + @Element(name = "EventBridgeConfiguration", required = false) + EventBridgeConfiguration eventBridgeConfiguration) { + this.cloudFunctionConfigurations = cloudFunctionConfigurations; + this.queueConfigurations = queueConfigurations; + this.topicConfigurations = topicConfigurations; + this.eventBridgeConfiguration = eventBridgeConfiguration; } - /** Sets cloud function configuration list. */ - public void setCloudFunctionConfigurationList( - List cloudFunctionConfigurationList) { - this.cloudFunctionConfigurationList = - cloudFunctionConfigurationList == null - ? null - : Utils.unmodifiableList(cloudFunctionConfigurationList); + /** Returns cloud function configuration. */ + public List cloudFunctionConfigurations() { + return Utils.unmodifiableList(cloudFunctionConfigurations); } /** Returns queue configuration list. */ - public List queueConfigurationList() { - return Utils.unmodifiableList(queueConfigurationList); - } - - /** Sets queue configuration list. */ - public void setQueueConfigurationList(List queueConfigurationList) { - this.queueConfigurationList = - queueConfigurationList == null ? null : Utils.unmodifiableList(queueConfigurationList); + public List queueConfigurations() { + return Utils.unmodifiableList(queueConfigurations); } /** Returns topic configuration list. */ - public List topicConfigurationList() { - return Utils.unmodifiableList(topicConfigurationList); - } - - /** Sets topic configuration list. */ - public void setTopicConfigurationList(List topicConfigurationList) { - this.topicConfigurationList = - topicConfigurationList == null ? null : Utils.unmodifiableList(topicConfigurationList); + public List topicConfigurations() { + return Utils.unmodifiableList(topicConfigurations); } public EventBridgeConfiguration eventBridgeConfiguration() { return this.eventBridgeConfiguration; } - public void setEventBridgeConfiguration(EventBridgeConfiguration config) { - this.eventBridgeConfiguration = config; + @Override + public String toString() { + return String.format( + "NotificationConfiguration{cloudFunctionConfigurations=%s, queueConfigurations=%s," + + " topicConfigurations=%s, eventBridgeConfiguration=%s}", + Utils.stringify(cloudFunctionConfigurations), + Utils.stringify(queueConfigurations), + Utils.stringify(topicConfigurations), + Utils.stringify(eventBridgeConfiguration)); } + /** Event bridge configuration of {@link NotificationConfiguration}. */ @Root(name = "EventBridgeConfiguration") - public static class EventBridgeConfiguration {} + public static class EventBridgeConfiguration { + @Override + public String toString() { + return String.format("EventBridgeConfiguration{}"); + } + } + + /** + * Common configuration of {@link CloudFunctionConfiguration}, {@link QueueConfiguration} and + * {@link TopicConfiguration}. + */ + public abstract static class BaseConfiguration { + @Element(name = "Id", required = false) + private String id; + + @ElementList(entry = "Event", inline = true) + private List events; + + @Element(name = "Filter", required = false) + private Filter filter; + + public BaseConfiguration(String id, @Nonnull List events, Filter filter) { + this.id = id; + this.events = + Utils.unmodifiableList(Objects.requireNonNull(events, "Events must not be null")); + this.filter = filter; + } + + public String id() { + return id; + } + + public List events() { + return Utils.unmodifiableList(events); + } + + public Filter filter() { + return filter; + } + + @Override + public String toString() { + return String.format( + "id=%s, events=%s, filter=%s", + Utils.stringify(id), Utils.stringify(events), Utils.stringify(filter)); + } + } + + /** Filter configuration of {@link BaseConfiguration}. */ + @Root(name = "Filter") + public static class Filter { + @Path(value = "S3Key") + @ElementList(name = "FilterRule", inline = true) + private List rules; + + public Filter( + @Nonnull @Path(value = "S3Key") @ElementList(name = "FilterRule", inline = true) + List rules) { + Objects.requireNonNull(rules, "Filter rules must not be null"); + if (rules.size() < 1) { + throw new IllegalArgumentException("At least one rule must be provided"); + } + if (rules.size() > 2) { + throw new IllegalArgumentException("Maximum two rules must be provided"); + } + if (rules.size() == 2 && rules.get(0).name().equals(rules.get(1).name())) { + throw new IllegalArgumentException( + "Two rules '" + rules.get(0).name() + "' must not be same"); + } + this.rules = Utils.unmodifiableList(rules); + } + + public Filter(@Nonnull String prefix, @Nonnull String suffix) { + if (prefix == null && suffix == null) { + throw new IllegalArgumentException("Either prefix or suffix must be provided"); + } + List rules = new LinkedList<>(); + if (prefix != null) rules.add(FilterRule.newPrefixFilterRule(prefix)); + if (suffix != null) rules.add(FilterRule.newSuffixFilterRule(suffix)); + this.rules = Utils.unmodifiableList(rules); + } + + public List rules() { + return rules; + } + + @Override + public String toString() { + return String.format("Filter{rules=%s}", Utils.stringify(rules)); + } + } + + /** Filter rule configuration of {@link Filter}. */ + @Root(name = "FilterRule") + public static class FilterRule { + @Element(name = "Name") + private String name; + + @Element(name = "Value") + private String value; + + public FilterRule( + @Nonnull @Element(name = "Name") String name, + @Nonnull @Element(name = "Value") String value) { + Objects.requireNonNull(name, "Name must not be null"); + if (!"prefix".equals(name) && !"suffix".equals(name)) { + throw new IllegalArgumentException("Name must be 'prefix' or 'suffix'"); + } + Objects.requireNonNull(value, "Value must not be null"); + this.name = name; + this.value = value; + } + + public static FilterRule newPrefixFilterRule(@Nonnull String value) { + return new FilterRule("prefix", value); + } + + public static FilterRule newSuffixFilterRule(@Nonnull String value) { + return new FilterRule("suffix", value); + } + + public String name() { + return name; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.format( + "FilterRule{name=%s, value=%s}", Utils.stringify(name), Utils.stringify(value)); + } + } + + /** Cloud function configuration of {@link NotificationConfiguration}. */ + @Root(name = "CloudFunctionConfiguration", strict = false) + public static class CloudFunctionConfiguration extends BaseConfiguration { + @Element(name = "CloudFunction") + private String cloudFunction; + + public CloudFunctionConfiguration( + @Nonnull @Element(name = "CloudFunction") String cloudFunction, + @Element(name = "Id", required = false) String id, + @Nonnull @ElementList(entry = "Event", inline = true) List events, + @Element(name = "Filter", required = false) Filter filter) { + super(id, events, filter); + this.cloudFunction = cloudFunction; + } + + /** Returns cloudFunction. */ + public String cloudFunction() { + return cloudFunction; + } + + @Override + public String toString() { + return String.format( + "CloudFunctionConfiguration{cloudFunction=%s, %s}", + Utils.stringify(cloudFunction), super.toString()); + } + } + + /** Queue configuration of {@link NotificationConfiguration}. */ + @Root(name = "QueueConfiguration", strict = false) + public static class QueueConfiguration extends BaseConfiguration { + @Element(name = "Queue") + private String queue; + + public QueueConfiguration( + @Nonnull @Element(name = "Queue") String queue, + @Element(name = "Id", required = false) String id, + @Nonnull @ElementList(entry = "Event", inline = true) List events, + @Element(name = "Filter", required = false) Filter filter) { + super(id, events, filter); + this.queue = queue; + } + + /** Returns queue. */ + public String queue() { + return queue; + } + + @Override + public String toString() { + return String.format( + "QueueConfiguration{queue=%s, %s}", Utils.stringify(queue), super.toString()); + } + } + + /** Topic configuration of {@link NotificationConfiguration}. */ + @Root(name = "TopicConfiguration", strict = false) + public static class TopicConfiguration extends BaseConfiguration { + @Element(name = "Topic") + private String topic; + + public TopicConfiguration( + @Nonnull @Element(name = "Topic") String topic, + @Element(name = "Id", required = false) String id, + @Nonnull @ElementList(entry = "Event", inline = true) List events, + @Element(name = "Filter", required = false) Filter filter) { + super(id, events, filter); + this.topic = topic; + } + + /** Returns topic. */ + public String topic() { + return topic; + } + + @Override + public String toString() { + return String.format( + "TopicConfiguration{topic=%s, %s}", Utils.stringify(topic), super.toString()); + } + } } diff --git a/api/src/main/java/io/minio/messages/NotificationRecords.java b/api/src/main/java/io/minio/messages/NotificationRecords.java index 8f0dabe8a..944901e9f 100644 --- a/api/src/main/java/io/minio/messages/NotificationRecords.java +++ b/api/src/main/java/io/minio/messages/NotificationRecords.java @@ -18,13 +18,16 @@ package io.minio.messages; import com.fasterxml.jackson.annotation.JsonProperty; +import io.minio.Time; import io.minio.Utils; +import java.time.ZonedDateTime; import java.util.List; +import java.util.Map; /** - * Object representation of JSON format of Event - * Message Structure. + * JSON format of Notification + * Content Structure. */ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value = "UwF", @@ -36,4 +39,240 @@ public class NotificationRecords { public List events() { return Utils.unmodifiableList(events); } + + @Override + public String toString() { + return String.format("NotificationRecords{events=%s}", Utils.stringify(events)); + } + + /** Event information of {@link NotificationRecords}. */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "UuF", + justification = "eventVersion and eventSource are available for completeness") + public static class Event { + @JsonProperty private String eventVersion; + @JsonProperty private String eventSource; + @JsonProperty private String awsRegion; + @JsonProperty private String eventName; + @JsonProperty private Identity userIdentity; + @JsonProperty private Map requestParameters; + @JsonProperty private Map responseElements; + @JsonProperty private S3 s3; + @JsonProperty private Source source; + @JsonProperty private Time.S3Time eventTime; + + public String eventVersion() { + return eventVersion; + } + + public String eventSource() { + return eventSource; + } + + public String awsRegion() { + return awsRegion; + } + + public String eventName() { + return eventName; + } + + public String userIdentity() { + return userIdentity == null ? null : userIdentity.principalId(); + } + + public Map requestParameters() { + return Utils.unmodifiableMap(requestParameters); + } + + public Map responseElements() { + return Utils.unmodifiableMap(responseElements); + } + + public Bucket bucket() { + return s3 == null ? null : s3.bucket(); + } + + public Object object() { + return s3 == null ? null : s3.object(); + } + + public Source source() { + return source; + } + + public ZonedDateTime eventTime() { + return eventTime == null ? null : eventTime.toZonedDateTime(); + } + + @Override + public String toString() { + return String.format( + "Event{eventVersion=%s, eventSource=%s, awsRegion=%s, eventName=%s, userIdentity=%s," + + " requestParameters=%s, responseElements=%s, s3=%s, source=%s, eventTime=%s}", + Utils.stringify(eventVersion), + Utils.stringify(eventSource), + Utils.stringify(awsRegion), + Utils.stringify(eventName), + Utils.stringify(userIdentity), + Utils.stringify(requestParameters), + Utils.stringify(responseElements), + Utils.stringify(s3), + Utils.stringify(source), + Utils.stringify(eventTime)); + } + + /** Identity information of {@link Event}. */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "UwF", + justification = "Everything in this class is initialized by JSON unmarshalling.") + public static class Identity { + @JsonProperty private String principalId; + + public String principalId() { + return principalId; + } + + @Override + public String toString() { + return String.format("Identity{principalId=%s}", Utils.stringify(principalId)); + } + } + + /** Bucket information of {@link Event}. */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "UwF", + justification = "Everything in this class is initialized by JSON unmarshalling.") + public static class Bucket { + @JsonProperty private String name; + @JsonProperty private Identity ownerIdentity; + @JsonProperty private String arn; + + public String name() { + return name; + } + + public String ownerIdentity() { + return ownerIdentity == null ? null : ownerIdentity.principalId(); + } + + public String arn() { + return arn; + } + + @Override + public String toString() { + return String.format( + "Bucket{name=%s, ownerIdentity=%s, arn=%s}", + Utils.stringify(name), Utils.stringify(ownerIdentity), Utils.stringify(arn)); + } + } + + /** Object information of {@link Event}. */ + public static class Object { + @JsonProperty private String key; + @JsonProperty private long size; + @JsonProperty private String eTag; + @JsonProperty private String versionId; + @JsonProperty private String sequencer; + @JsonProperty private Map userMetadata; // MinIO specific extension. + + public String key() { + return key; + } + + public long size() { + return size; + } + + public String etag() { + return eTag; + } + + public String versionId() { + return versionId; + } + + public String sequencer() { + return sequencer; + } + + public Map userMetadata() { + return Utils.unmodifiableMap(userMetadata); + } + + @Override + public String toString() { + return String.format( + "Object{key=%s, size=%d, eTag=%s, versionId=%s, sequencer=%s, userMetadata=%s}", + Utils.stringify(key), + size, + Utils.stringify(eTag), + Utils.stringify(versionId), + Utils.stringify(sequencer), + Utils.stringify(userMetadata)); + } + } + + /** S3 information of {@link Event}. */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = {"UwF", "UuF"}, + justification = + "Everything in this class is initialized by JSON unmarshalling " + + "and s3SchemaVersion/configurationId are available for completeness.") + public static class S3 { + @JsonProperty private String s3SchemaVersion; + @JsonProperty private String configurationId; + @JsonProperty private Bucket bucket; + @JsonProperty private Object object; + + public Bucket bucket() { + return bucket; + } + + public Object object() { + return object; + } + + @Override + public String toString() { + return String.format( + "S3{s3SchemaVersion=%s, configurationId=%s, bucket=%s, object=%s}", + Utils.stringify(s3SchemaVersion), + Utils.stringify(configurationId), + Utils.stringify(bucket), + Utils.stringify(object)); + } + } + + /** Source information of {@link Event}. */ + /** This is MinIO extension. */ + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "UwF", + justification = "Everything in this class is initialized by JSON unmarshalling.") + public static class Source { + @JsonProperty private String host; + @JsonProperty private String port; + @JsonProperty private String userAgent; + + public String host() { + return host; + } + + public String port() { + return port; + } + + public String userAgent() { + return userAgent; + } + + @Override + public String toString() { + return String.format( + "Source{host=%s, port=%s, userAgent=%s}", + Utils.stringify(host), Utils.stringify(port), Utils.stringify(userAgent)); + } + } + } } diff --git a/api/src/main/java/io/minio/messages/ObjectLockConfiguration.java b/api/src/main/java/io/minio/messages/ObjectLockConfiguration.java index 463054f7f..e290a03f1 100644 --- a/api/src/main/java/io/minio/messages/ObjectLockConfiguration.java +++ b/api/src/main/java/io/minio/messages/ObjectLockConfiguration.java @@ -16,12 +16,16 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; +import org.simpleframework.xml.ElementUnion; import org.simpleframework.xml.Namespace; +import org.simpleframework.xml.Path; import org.simpleframework.xml.Root; +import org.simpleframework.xml.Text; /** - * Object representation of request XML of PutObjectLockConfiguration * API and response XML of GetObjectLockConfiguration @@ -54,4 +58,123 @@ public RetentionMode mode() { public RetentionDuration duration() { return (rule != null) ? rule.duration() : null; } + + @Override + public String toString() { + return String.format( + "ObjectLockConfiguration{objectLockEnabled=%s, rule=%s}", + Utils.stringify(objectLockEnabled), Utils.stringify(rule)); + } + + /** Rule information of {@link ObjectLockConfiguration}. */ + @Root(name = "Rule", strict = false) + public static class Rule { + @Path(value = "DefaultRetention") + @Element(name = "Mode", required = false) + private RetentionMode mode; + + @Path(value = "DefaultRetention") + @ElementUnion({ + @Element(name = "Days", type = RetentionDurationDays.class, required = false), + @Element(name = "Years", type = RetentionDurationYears.class, required = false) + }) + private RetentionDuration duration; + + public Rule( + @Element(name = "Mode", required = false) RetentionMode mode, + @ElementUnion({ + @Element(name = "Days", type = RetentionDurationDays.class, required = false), + @Element(name = "Years", type = RetentionDurationYears.class, required = false) + }) + RetentionDuration duration) { + if (mode != null && duration != null) { + this.mode = mode; + this.duration = duration; + } else if (mode != null || duration != null) { + if (mode == null) { + throw new IllegalArgumentException("mode is null"); + } + throw new IllegalArgumentException("duration is null"); + } + } + + public RetentionMode mode() { + return mode; + } + + public RetentionDuration duration() { + return duration; + } + + @Override + public String toString() { + return String.format( + "Rule{mode=%s, duration=%s}", Utils.stringify(mode), Utils.stringify(duration)); + } + } + + /** Interface represents retention duration of {@link Rule}. */ + public static interface RetentionDuration { + public RetentionDurationUnit unit(); + + public int duration(); + } + + /** Retention duration unit. */ + public static enum RetentionDurationUnit { + DAYS, + YEARS; + } + + /** Retention duration days of {@link Rule}. */ + @Root(name = "Days") + public static class RetentionDurationDays implements RetentionDuration { + @Text(required = false) + private Integer days; + + public RetentionDurationDays() {} + + public RetentionDurationDays(int days) { + this.days = Integer.valueOf(days); + } + + public RetentionDurationUnit unit() { + return RetentionDurationUnit.DAYS; + } + + public int duration() { + return days; + } + + @Override + public String toString() { + return String.format("RetentionDurationDays{%s}", Utils.stringify(days)); + } + } + + /** Retention duration years of {@link Rule}. */ + @Root(name = "Years") + public static class RetentionDurationYears implements RetentionDuration { + @Text(required = false) + private Integer years; + + public RetentionDurationYears() {} + + public RetentionDurationYears(int years) { + this.years = Integer.valueOf(years); + } + + public RetentionDurationUnit unit() { + return RetentionDurationUnit.YEARS; + } + + public int duration() { + return years; + } + + @Override + public String toString() { + return String.format("RetentionDurationYears{%s}", Utils.stringify(years)); + } + } } diff --git a/api/src/main/java/io/minio/messages/ObjectMetadata.java b/api/src/main/java/io/minio/messages/ObjectMetadata.java deleted file mode 100644 index d705ca79e..000000000 --- a/api/src/main/java/io/minio/messages/ObjectMetadata.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2020 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.minio.Utils; -import java.util.Map; - -/** Helper class to denote object information for {@link EventMetadata}. */ -public class ObjectMetadata { - @JsonProperty private String key; - @JsonProperty private long size; - @JsonProperty private String eTag; - @JsonProperty private String versionId; - @JsonProperty private String sequencer; - @JsonProperty private Map userMetadata; // MinIO specific extension. - - public String key() { - return key; - } - - public long size() { - return size; - } - - public String etag() { - return eTag; - } - - public String versionId() { - return versionId; - } - - public String sequencer() { - return sequencer; - } - - public Map userMetadata() { - return Utils.unmodifiableMap(userMetadata); - } -} diff --git a/api/src/main/java/io/minio/messages/OutputLocation.java b/api/src/main/java/io/minio/messages/OutputLocation.java deleted file mode 100644 index e2f8091a7..000000000 --- a/api/src/main/java/io/minio/messages/OutputLocation.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote output location information of {@link RestoreRequest}. */ -@Root(name = "OutputLocation") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class OutputLocation { - @Element(name = "S3") - private S3OutputLocation s3OutputLocation; - - public OutputLocation(@Nonnull S3OutputLocation s3OutputLocation) { - this.s3OutputLocation = - Objects.requireNonNull(s3OutputLocation, "S3OutputLocation must not be null"); - } -} diff --git a/api/src/main/java/io/minio/messages/OutputSerialization.java b/api/src/main/java/io/minio/messages/OutputSerialization.java index 20ebe898e..2405eb71a 100644 --- a/api/src/main/java/io/minio/messages/OutputSerialization.java +++ b/api/src/main/java/io/minio/messages/OutputSerialization.java @@ -19,32 +19,86 @@ import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; -/** - * Helper class to denote Output Serialization information of {@link SelectObjectContentRequest}. - */ +/** Output Serialization information of {@link SelectObjectContentRequest}. */ @Root(name = "OutputSerialization") @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public class OutputSerialization { @Element(name = "CSV", required = false) - private CsvOutputSerialization csv; + private CSV csv; @Element(name = "JSON", required = false) - private JsonOutputSerialization json; + private JSON json; + + private OutputSerialization(CSV csv, JSON json) { + this.csv = csv; + this.json = json; + } /** Constructs a new OutputSerialization object with CSV. */ - public OutputSerialization( + public static OutputSerialization newCSV( Character fieldDelimiter, Character quoteCharacter, Character quoteEscapeCharacter, QuoteFields quoteFields, Character recordDelimiter) { - this.csv = - new CsvOutputSerialization( - fieldDelimiter, quoteCharacter, quoteEscapeCharacter, quoteFields, recordDelimiter); + return new OutputSerialization( + new CSV(fieldDelimiter, quoteCharacter, quoteEscapeCharacter, quoteFields, recordDelimiter), + null); } /** Constructs a new OutputSerialization object with JSON. */ - public OutputSerialization(Character recordDelimiter) { - this.json = new JsonOutputSerialization(recordDelimiter); + public static OutputSerialization newJSON(Character recordDelimiter) { + return new OutputSerialization(null, new JSON(recordDelimiter)); + } + + /** CSV output serialization information of {@link OutputSerialization}. */ + @Root(name = "CSV") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class CSV { + @Element(name = "FieldDelimiter", required = false) + private Character fieldDelimiter; + + @Element(name = "QuoteCharacter", required = false) + private Character quoteCharacter; + + @Element(name = "QuoteEscapeCharacter", required = false) + private Character quoteEscapeCharacter; + + @Element(name = "QuoteFields", required = false) + private QuoteFields quoteFields; + + @Element(name = "RecordDelimiter", required = false) + private Character recordDelimiter; + + public CSV( + Character fieldDelimiter, + Character quoteCharacter, + Character quoteEscapeCharacter, + QuoteFields quoteFields, + Character recordDelimiter) { + this.fieldDelimiter = fieldDelimiter; + this.quoteCharacter = quoteCharacter; + this.quoteEscapeCharacter = quoteEscapeCharacter; + this.quoteFields = quoteFields; + this.recordDelimiter = recordDelimiter; + } + } + + /** JSON output serialization information of {@link OutputSerialization}. */ + @Root(name = "JSON") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class JSON { + @Element(name = "RecordDelimiter", required = false) + private Character recordDelimiter; + + public JSON(Character recordDelimiter) { + this.recordDelimiter = recordDelimiter; + } + } + + /** Quotation field type of {@link CSV}. */ + public static enum QuoteFields { + ALWAYS, + ASNEEDED; } } diff --git a/api/src/main/java/io/minio/messages/Owner.java b/api/src/main/java/io/minio/messages/Owner.java index 28ffa998b..18e29a1b9 100644 --- a/api/src/main/java/io/minio/messages/Owner.java +++ b/api/src/main/java/io/minio/messages/Owner.java @@ -16,13 +16,14 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; /** - * Helper class to denote owner information for {@link ListAllMyBucketsResult}, {@link - * ListBucketResultV1}, {@link ListBucketResultV2}, {@link ListVersionsResult}, {@link - * ListMultipartUploadsResult} and {@link ListPartsResult}. + * Owner information for {@link ListAllMyBucketsResult}, {@link ListBucketResultV1}, {@link + * ListBucketResultV2}, {@link ListVersionsResult}, {@link ListMultipartUploadsResult} and {@link + * ListPartsResult}. */ @Root(name = "Owner", strict = false) public class Owner { @@ -43,4 +44,10 @@ public String id() { public String displayName() { return displayName; } + + @Override + public String toString() { + return String.format( + "Owner{id=%s, displayName=%s}", Utils.stringify(id), Utils.stringify(displayName)); + } } diff --git a/api/src/main/java/io/minio/messages/ParquetInputSerialization.java b/api/src/main/java/io/minio/messages/ParquetInputSerialization.java deleted file mode 100644 index d40e85960..000000000 --- a/api/src/main/java/io/minio/messages/ParquetInputSerialization.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Root; - -/** - * Helper class to denote Parquet input serialization request XML as per {@link - * SelectObjectContentRequest}. - */ -@Root(name = "Parquet") -public class ParquetInputSerialization {} diff --git a/api/src/main/java/io/minio/messages/Part.java b/api/src/main/java/io/minio/messages/Part.java index d8aac178e..c6b7e841b 100644 --- a/api/src/main/java/io/minio/messages/Part.java +++ b/api/src/main/java/io/minio/messages/Part.java @@ -16,16 +16,18 @@ package io.minio.messages; +import io.minio.Time; +import io.minio.Utils; import java.time.ZonedDateTime; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; /** - * Helper class to denote Part information of a multipart upload and used in {@link - * CompleteMultipartUpload} and {@link ListPartsResult}. + * Part information of {@link CompleteMultipartUpload}, {@link CompleteMultipartUpload} and {@link + * ListPartsResult}. */ @Root(name = "Part", strict = false) -public class Part { +public class Part extends Checksum { @Element(name = "PartNumber", required = false) private int partNumber; @@ -33,36 +35,18 @@ public class Part { private String etag; @Element(name = "LastModified", required = false) - private ResponseDate lastModified; + private Time.S3Time lastModified; @Element(name = "Size", required = false) private Long size; - @Element(name = "ChecksumCRC32", required = false) - private String checksumCRC32; - - @Element(name = "ChecksumCRC32C", required = false) - private String checksumCRC32C; - - @Element(name = "ChecksumCRC64NVME", required = false) - private String checksumCRC64NVME; - - @Element(name = "ChecksumSHA1", required = false) - private String checksumSHA1; - - @Element(name = "ChecksumSHA256", required = false) - private String checksumSHA256; - public Part() {} - /** Constructs a new Part object with given part number and ETag. */ public Part(int partNumber, String etag) { - this.partNumber = partNumber; this.etag = etag; } - /** Constructs a new Part object with given values. */ public Part( int partNumber, String etag, @@ -71,52 +55,41 @@ public Part( String checksumCRC64NVME, String checksumSHA1, String checksumSHA256) { + super(checksumCRC32, checksumCRC32C, checksumCRC64NVME, checksumSHA1, checksumSHA256, null); this.partNumber = partNumber; this.etag = etag; - this.checksumCRC32 = checksumCRC32; - this.checksumCRC32C = checksumCRC32C; - this.checksumCRC64NVME = checksumCRC64NVME; - this.checksumSHA1 = checksumSHA1; - this.checksumSHA256 = checksumSHA256; } - /** Returns part number. */ + public Part(CopyPartResult result, int partNumber) { + super(result); + this.etag = result.etag(); + this.partNumber = partNumber; + } + public int partNumber() { return partNumber; } - /** Returns ETag. */ public String etag() { return etag.replaceAll("\"", ""); } - /** Returns last modified time. */ public ZonedDateTime lastModified() { - return lastModified.zonedDateTime(); + return lastModified == null ? null : lastModified.toZonedDateTime(); } - /** Returns part size. */ public long partSize() { return size; } - public String checksumCRC32() { - return checksumCRC32; - } - - public String checksumCRC32C() { - return checksumCRC32C; - } - - public String checksumCRC64NVME() { - return checksumCRC64NVME; - } - - public String checksumSHA1() { - return checksumSHA1; - } - - public String checksumSHA256() { - return checksumSHA256; + @Override + public String toString() { + return String.format( + "Part{partNumber=%s, etag=%s, lastModified=%s, size=%s, %s}", + Utils.stringify(partNumber), + Utils.stringify(etag), + Utils.stringify(lastModified), + Utils.stringify(size), + super.stringify()); } } diff --git a/api/src/main/java/io/minio/messages/Permission.java b/api/src/main/java/io/minio/messages/Permission.java deleted file mode 100644 index a86d43007..000000000 --- a/api/src/main/java/io/minio/messages/Permission.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Root; - -/** Permission represents type of grantee. */ -@Root(name = "Permission") -public enum Permission { - FULL_CONTROL, - WRITE, - WRITE_ACP, - READ, - READ_ACP; -} diff --git a/api/src/main/java/io/minio/messages/Prefix.java b/api/src/main/java/io/minio/messages/Prefix.java deleted file mode 100644 index 4a27a7bc4..000000000 --- a/api/src/main/java/io/minio/messages/Prefix.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote Prefix information in {@link ListBucketResultV1}, {@link - * ListBucketResultV2} and {@link ListVersionsResult}. - */ -@Root(name = "CommonPrefixes", strict = false) -public class Prefix { - @Element(name = "Prefix") - private String prefix; - - public Prefix() {} - - public Item toItem() { - return new Contents(prefix); - } -} diff --git a/api/src/main/java/io/minio/messages/PrefixConverter.java b/api/src/main/java/io/minio/messages/PrefixConverter.java index 2b7e51560..8fb584c28 100644 --- a/api/src/main/java/io/minio/messages/PrefixConverter.java +++ b/api/src/main/java/io/minio/messages/PrefixConverter.java @@ -21,8 +21,8 @@ import org.simpleframework.xml.stream.OutputNode; /** - * XML converter class for prefix due to SimpleXML limitation in converting empty tag - * to empty string. + * XML converter for prefix due to SimpleXML limitation in converting empty tag to + * empty string. */ public class PrefixConverter implements Converter { @Override diff --git a/api/src/main/java/io/minio/messages/Progress.java b/api/src/main/java/io/minio/messages/Progress.java index 71ba29590..ef1668139 100644 --- a/api/src/main/java/io/minio/messages/Progress.java +++ b/api/src/main/java/io/minio/messages/Progress.java @@ -16,10 +16,23 @@ package io.minio.messages; +import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; -/** Helper class to denote Progress information of S3 select response message. */ +/** Progress information of S3 select response message. */ @Root(name = "Progress", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class Progress extends Stats {} +public class Progress extends Stats { + public Progress( + @Element(name = "BytesScanned", required = false) Long bytesScanned, + @Element(name = "BytesProcessed", required = false) Long bytesProcessed, + @Element(name = "BytesReturned", required = false) Long bytesReturned) { + super(bytesScanned, bytesProcessed, bytesReturned); + } + + @Override + public String toString() { + return String.format("Progress{%s}", super.stringify()); + } +} diff --git a/api/src/main/java/io/minio/messages/QuoteFields.java b/api/src/main/java/io/minio/messages/QuoteFields.java deleted file mode 100644 index a33e1871f..000000000 --- a/api/src/main/java/io/minio/messages/QuoteFields.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -/** Indicates whether to use quotation marks around output fields. */ -public enum QuoteFields { - ALWAYS, - ASNEEDED; -} diff --git a/api/src/main/java/io/minio/messages/ReplicaModifications.java b/api/src/main/java/io/minio/messages/ReplicaModifications.java deleted file mode 100644 index dc18cf9ed..000000000 --- a/api/src/main/java/io/minio/messages/ReplicaModifications.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2022 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote replica modifications information for {@link SourceSelectionCriteria}. */ -@Root(name = "ReplicaModifications") -public class ReplicaModifications { - @Element(name = "Status") - private Status status; - - public ReplicaModifications(@Nonnull @Element(name = "Status") Status status) { - this.status = Objects.requireNonNull(status, "Status must not be null"); - } - - public Status status() { - return this.status; - } -} diff --git a/api/src/main/java/io/minio/messages/ReplicationConfiguration.java b/api/src/main/java/io/minio/messages/ReplicationConfiguration.java index 3dcb87629..f2695a511 100644 --- a/api/src/main/java/io/minio/messages/ReplicationConfiguration.java +++ b/api/src/main/java/io/minio/messages/ReplicationConfiguration.java @@ -25,9 +25,10 @@ import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; /** - * Object representation of request XML of PutBucketReplication * API and response XML of GetBucketReplication @@ -40,12 +41,11 @@ public class ReplicationConfiguration { private String role; @ElementList(name = "Rule", inline = true) - private List rules; + private List rules; - /** Constructs new replication configuration. */ public ReplicationConfiguration( @Nullable @Element(name = "Role", required = false) String role, - @Nonnull @ElementList(name = "Rule", inline = true) List rules) { + @Nonnull @ElementList(name = "Rule", inline = true) List rules) { this.role = role; // Role is not applicable in MinIO server and it is optional. this.rules = Utils.unmodifiableList(Objects.requireNonNull(rules, "Rules must not be null")); @@ -61,7 +61,525 @@ public String role() { return role; } - public List rules() { + public List rules() { return Utils.unmodifiableList(rules); } + + @Override + public String toString() { + return String.format( + "ReplicationConfiguration{role=%s, rules=%s}", + Utils.stringify(role), Utils.stringify(rules)); + } + + /** Rule information of {@link ReplicationConfiguration}. */ + @Root(name = "Rule") + public static class Rule { + @Element(name = "DeleteMarkerReplication", required = false) + private DeleteMarkerReplication deleteMarkerReplication; + + @Element(name = "Destination") + private Destination destination; + + @Element(name = "ExistingObjectReplication", required = false) + private ExistingObjectReplication existingObjectReplication; + + @Element(name = "Filter", required = false) + private Filter filter; + + @Element(name = "ID", required = false) + private String id; + + @Element(name = "Prefix", required = false) + @Convert(PrefixConverter.class) + private String prefix; + + @Element(name = "Priority", required = false) + private Integer priority; + + @Element(name = "SourceSelectionCriteria", required = false) + private SourceSelectionCriteria sourceSelectionCriteria; + + @Element(name = "DeleteReplication", required = false) + private DeleteReplication deleteReplication; // This is MinIO specific extension. + + @Element(name = "Status") + private Status status; + + public Rule( + @Nullable @Element(name = "DeleteMarkerReplication", required = false) + DeleteMarkerReplication deleteMarkerReplication, + @Nonnull @Element(name = "Destination") Destination destination, + @Nullable @Element(name = "ExistingObjectReplication", required = false) + ExistingObjectReplication existingObjectReplication, + @Nullable @Element(name = "Filter", required = false) Filter filter, + @Nullable @Element(name = "ID", required = false) String id, + @Nullable @Element(name = "Prefix", required = false) String prefix, + @Nullable @Element(name = "Priority", required = false) Integer priority, + @Nullable @Element(name = "SourceSelectionCriteria", required = false) + SourceSelectionCriteria sourceSelectionCriteria, + @Nullable @Element(name = "DeleteReplication", required = false) + DeleteReplication deleteReplication, + @Nonnull @Element(name = "Status") Status status) { + + if (filter != null && deleteMarkerReplication == null) { + deleteMarkerReplication = new DeleteMarkerReplication(null); + } + + if (id != null) { + id = id.trim(); + if (id.isEmpty()) throw new IllegalArgumentException("ID must be non-empty string"); + if (id.length() > 255) + throw new IllegalArgumentException("ID must be exceed 255 characters"); + } + + this.deleteMarkerReplication = deleteMarkerReplication; + this.destination = Objects.requireNonNull(destination, "Destination must not be null"); + this.existingObjectReplication = existingObjectReplication; + this.filter = filter; + this.id = id; + this.prefix = prefix; + this.priority = priority; + this.sourceSelectionCriteria = sourceSelectionCriteria; + this.deleteReplication = deleteReplication; + this.status = Objects.requireNonNull(status, "Status must not be null"); + } + + public Rule( + @Nullable @Element(name = "DeleteMarkerReplication", required = false) + DeleteMarkerReplication deleteMarkerReplication, + @Nonnull @Element(name = "Destination") Destination destination, + @Nullable @Element(name = "ExistingObjectReplication", required = false) + ExistingObjectReplication existingObjectReplication, + @Nullable @Element(name = "Filter", required = false) Filter filter, + @Nullable @Element(name = "ID", required = false) String id, + @Nullable @Element(name = "Prefix", required = false) String prefix, + @Nullable @Element(name = "Priority", required = false) Integer priority, + @Nullable @Element(name = "SourceSelectionCriteria", required = false) + SourceSelectionCriteria sourceSelectionCriteria, + @Nonnull @Element(name = "Status") Status status) { + this( + deleteMarkerReplication, + destination, + existingObjectReplication, + filter, + id, + prefix, + priority, + sourceSelectionCriteria, + null, + status); + } + + public DeleteMarkerReplication deleteMarkerReplication() { + return this.deleteMarkerReplication; + } + + public Destination destination() { + return this.destination; + } + + public ExistingObjectReplication existingObjectReplication() { + return this.existingObjectReplication; + } + + public Filter filter() { + return this.filter; + } + + public String id() { + return this.id; + } + + public String prefix() { + return this.prefix; + } + + public Integer priority() { + return this.priority; + } + + public SourceSelectionCriteria sourceSelectionCriteria() { + return this.sourceSelectionCriteria; + } + + public DeleteReplication deleteReplication() { + return this.deleteReplication; + } + + public Status status() { + return this.status; + } + + @Override + public String toString() { + return String.format( + "Rule{deleteMarkerReplication=%s, destination=%s, existingObjectReplication=%s," + + " filter=%s, id=%s, prefix=%s, priority=%s, sourceSelectionCriteria=%s," + + " deleteReplication=%s, status=%s}", + Utils.stringify(deleteMarkerReplication), + Utils.stringify(destination), + Utils.stringify(existingObjectReplication), + Utils.stringify(filter), + Utils.stringify(id), + Utils.stringify(prefix), + Utils.stringify(priority), + Utils.stringify(sourceSelectionCriteria), + Utils.stringify(deleteReplication), + Utils.stringify(status)); + } + } + + /** Delete marker replication information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "DeleteMarkerReplication") + public static class DeleteMarkerReplication { + @Element(name = "Status", required = false) + private Status status; + + public DeleteMarkerReplication( + @Nullable @Element(name = "Status", required = false) Status status) { + this.status = (status == null) ? Status.DISABLED : status; + } + + public Status status() { + return status; + } + + @Override + public String toString() { + return String.format("DeleteMarkerReplication{status=%s}", Utils.stringify(status)); + } + } + + /** Destination information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "Destination") + public static class Destination { + @Element(name = "AccessControlTranslation", required = false) + private AccessControlTranslation accessControlTranslation; + + @Element(name = "Account", required = false) + private String account; + + @Element(name = "Bucket") + private String bucketArn; + + @Element(name = "EncryptionConfiguration", required = false) + private EncryptionConfiguration encryptionConfiguration; + + @Element(name = "Metrics", required = false) + private Metrics metrics; + + @Element(name = "ReplicationTime", required = false) + private ReplicationTime replicationTime; + + @Element(name = "StorageClass", required = false) + private String storageClass; + + public Destination( + @Nullable @Element(name = "AccessControlTranslation", required = false) + AccessControlTranslation accessControlTranslation, + @Nullable @Element(name = "Account", required = false) String account, + @Nonnull @Element(name = "Bucket") String bucketArn, + @Nullable @Element(name = "EncryptionConfiguration", required = false) + EncryptionConfiguration encryptionConfiguration, + @Nullable @Element(name = "Metrics", required = false) Metrics metrics, + @Nullable @Element(name = "ReplicationTime", required = false) + ReplicationTime replicationTime, + @Nullable @Element(name = "StorageClass", required = false) String storageClass) { + this.accessControlTranslation = accessControlTranslation; + this.account = account; + this.bucketArn = Objects.requireNonNull(bucketArn, "Bucket ARN must not be null"); + this.encryptionConfiguration = encryptionConfiguration; + this.metrics = metrics; + this.replicationTime = replicationTime; + this.storageClass = storageClass; + } + + public AccessControlTranslation accessControlTranslation() { + return this.accessControlTranslation; + } + + public String account() { + return this.account; + } + + public String bucketArn() { + return this.bucketArn; + } + + public EncryptionConfiguration encryptionConfiguration() { + return encryptionConfiguration; + } + + public Metrics metrics() { + return this.metrics; + } + + public ReplicationTime replicationTime() { + return this.replicationTime; + } + + public String storageClass() { + return this.storageClass; + } + + @Override + public String toString() { + return String.format( + "Destination{accessControlTranslation=%s, account=%s, bucketArn=%s," + + " encryptionConfiguration=%s, metrics=%s, replicationTime=%s, storageClass=%s}", + Utils.stringify(accessControlTranslation), + Utils.stringify(account), + Utils.stringify(bucketArn), + Utils.stringify(encryptionConfiguration), + Utils.stringify(metrics), + Utils.stringify(replicationTime), + Utils.stringify(storageClass)); + } + } + + /** Access control translation information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "AccessControlTranslation") + public static class AccessControlTranslation { + @Element(name = "Owner") + private String owner = "Destination"; + + public AccessControlTranslation(@Nonnull @Element(name = "Owner") String owner) { + this.owner = Objects.requireNonNull(owner, "Owner must not be null"); + } + + public String owner() { + return this.owner; + } + + @Override + public String toString() { + return String.format("AccessControlTranslation{owner=%s}", Utils.stringify(owner)); + } + } + + /** Encryption configuration information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "EncryptionConfiguration") + public static class EncryptionConfiguration { + @Element(name = "ReplicaKmsKeyID", required = false) + private String replicaKmsKeyID; + + public EncryptionConfiguration( + @Nullable @Element(name = "ReplicaKmsKeyID", required = false) String replicaKmsKeyID) { + this.replicaKmsKeyID = replicaKmsKeyID; + } + + public String replicaKmsKeyID() { + return this.replicaKmsKeyID; + } + + @Override + public String toString() { + return String.format( + "EncryptionConfiguration{replicaKmsKeyID=%s}", Utils.stringify(replicaKmsKeyID)); + } + } + + /** Metrics information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "Metrics") + public static class Metrics { + @Element(name = "EventThreshold") + private ReplicationTimeValue eventThreshold; + + @Element(name = "Status") + private Status status; + + public Metrics( + @Nonnull @Element(name = "EventThreshold") ReplicationTimeValue eventThreshold, + @Nonnull @Element(name = "Status") Status status) { + this.eventThreshold = + Objects.requireNonNull(eventThreshold, "Event threshold must not be null"); + this.status = Objects.requireNonNull(status, "Status must not be null"); + } + + public ReplicationTimeValue eventThreshold() { + return this.eventThreshold; + } + + public Status status() { + return this.status; + } + + @Override + public String toString() { + return String.format( + "Metrics{eventThreshold=%s, status=%s}", + Utils.stringify(eventThreshold), Utils.stringify(status)); + } + } + + /** Replication time information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "ReplicationTime") + public static class ReplicationTime { + @Element(name = "Time") + private ReplicationTimeValue time; + + @Element(name = "Status") + private Status status; + + public ReplicationTime( + @Nonnull @Element(name = "Time") ReplicationTimeValue time, + @Nonnull @Element(name = "Status") Status status) { + this.time = Objects.requireNonNull(time, "Time must not be null"); + this.status = Objects.requireNonNull(status, "Status must not be null"); + } + + public ReplicationTimeValue time() { + return this.time; + } + + public Status status() { + return this.status; + } + + @Override + public String toString() { + return String.format( + "ReplicationTime{time=%s, status=%s}", Utils.stringify(time), Utils.stringify(status)); + } + } + + /** Replication time value information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "ReplicationTimeValue") + public static class ReplicationTimeValue { + @Element(name = "Minutes", required = false) + private Integer minutes = 15; + + public ReplicationTimeValue( + @Nullable @Element(name = "Minutes", required = false) Integer minutes) { + this.minutes = minutes; + } + + public Integer minutes() { + return this.minutes; + } + + @Override + public String toString() { + return String.format("ReplicationTimeValue{minutes=%s}", Utils.stringify(minutes)); + } + } + + /** Existing object replication information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "ExistingObjectReplication") + public static class ExistingObjectReplication { + @Element(name = "Status") + private Status status; + + public ExistingObjectReplication(@Nonnull @Element(name = "Status") Status status) { + this.status = Objects.requireNonNull(status, "Status must not be null"); + } + + public Status status() { + return this.status; + } + + @Override + public String toString() { + return String.format("ExistingObjectReplication{status=%s}", Utils.stringify(status)); + } + } + + /** Source selection criteria information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "SourceSelectionCriteria") + public static class SourceSelectionCriteria { + @Element(name = "ReplicaModifications", required = false) + private ReplicaModifications replicaModifications; + + @Element(name = "SseKmsEncryptedObjects", required = false) + private SseKmsEncryptedObjects sseKmsEncryptedObjects; + + public SourceSelectionCriteria( + @Nullable @Element(name = "SseKmsEncryptedObjects", required = false) + SseKmsEncryptedObjects sseKmsEncryptedObjects, + @Nullable @Element(name = "ReplicaModifications", required = false) + ReplicaModifications replicaModifications) { + this.sseKmsEncryptedObjects = sseKmsEncryptedObjects; + this.replicaModifications = replicaModifications; + } + + public SourceSelectionCriteria(@Nullable SseKmsEncryptedObjects sseKmsEncryptedObjects) { + this(sseKmsEncryptedObjects, null); + } + + public ReplicaModifications replicaModifications() { + return this.replicaModifications; + } + + public SseKmsEncryptedObjects sseKmsEncryptedObjects() { + return this.sseKmsEncryptedObjects; + } + + @Override + public String toString() { + return String.format( + "SourceSelectionCriteria{replicaModifications=%s, sseKmsEncryptedObjects=%s}", + Utils.stringify(replicaModifications), Utils.stringify(sseKmsEncryptedObjects)); + } + } + + /** Replica modification information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "ReplicaModifications") + public static class ReplicaModifications { + @Element(name = "Status") + private Status status; + + public ReplicaModifications(@Nonnull @Element(name = "Status") Status status) { + this.status = Objects.requireNonNull(status, "Status must not be null"); + } + + public Status status() { + return this.status; + } + + @Override + public String toString() { + return String.format("ReplicaModifications{status=%s}", Utils.stringify(status)); + } + } + + /** SSE KMS encrypted objects information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "SseKmsEncryptedObjects") + public static class SseKmsEncryptedObjects { + @Element(name = "Status") + private Status status; + + public SseKmsEncryptedObjects(@Nonnull @Element(name = "Status") Status status) { + this.status = Objects.requireNonNull(status, "Status must not be null"); + } + + public Status status() { + return this.status; + } + + @Override + public String toString() { + return String.format("SseKmsEncryptedObjects{status=%s}", Utils.stringify(status)); + } + } + + /** Delete replication (MinIO extension) information of {@link ReplicationConfiguration.Rule}. */ + @Root(name = "DeleteReplication") + public static class DeleteReplication { + @Element(name = "Status", required = false) + private Status status; + + public DeleteReplication(@Nullable @Element(name = "Status", required = false) Status status) { + this.status = (status == null) ? Status.DISABLED : status; + } + + public Status status() { + return status; + } + + @Override + public String toString() { + return String.format("DeleteReplication{status=%s}", Utils.stringify(status)); + } + } } diff --git a/api/src/main/java/io/minio/messages/ReplicationDestination.java b/api/src/main/java/io/minio/messages/ReplicationDestination.java deleted file mode 100644 index 2a308d639..000000000 --- a/api/src/main/java/io/minio/messages/ReplicationDestination.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote Destination information for {@link ReplicationRule}. */ -@Root(name = "Destination") -public class ReplicationDestination { - @Element(name = "AccessControlTranslation", required = false) - private AccessControlTranslation accessControlTranslation; - - @Element(name = "Account", required = false) - private String account; - - @Element(name = "Bucket") - private String bucketArn; - - @Element(name = "EncryptionConfiguration", required = false) - private EncryptionConfiguration encryptionConfiguration; - - @Element(name = "Metrics", required = false) - private Metrics metrics; - - @Element(name = "ReplicationTime", required = false) - private ReplicationTime replicationTime; - - @Element(name = "StorageClass", required = false) - private String storageClass; - - public ReplicationDestination( - @Nullable @Element(name = "AccessControlTranslation", required = false) - AccessControlTranslation accessControlTranslation, - @Nullable @Element(name = "Account", required = false) String account, - @Nonnull @Element(name = "Bucket") String bucketArn, - @Nullable @Element(name = "EncryptionConfiguration", required = false) - EncryptionConfiguration encryptionConfiguration, - @Nullable @Element(name = "Metrics", required = false) Metrics metrics, - @Nullable @Element(name = "ReplicationTime", required = false) - ReplicationTime replicationTime, - @Nullable @Element(name = "StorageClass", required = false) String storageClass) { - this.accessControlTranslation = accessControlTranslation; - this.account = account; - this.bucketArn = Objects.requireNonNull(bucketArn, "Bucket ARN must not be null"); - this.encryptionConfiguration = encryptionConfiguration; - this.metrics = metrics; - this.replicationTime = replicationTime; - this.storageClass = storageClass; - } - - public AccessControlTranslation accessControlTranslation() { - return this.accessControlTranslation; - } - - public String account() { - return this.account; - } - - public String bucketArn() { - return this.bucketArn; - } - - public EncryptionConfiguration encryptionConfiguration() { - return encryptionConfiguration; - } - - public Metrics metrics() { - return this.metrics; - } - - public ReplicationTime replicationTime() { - return this.replicationTime; - } - - public String storageClass() { - return this.storageClass; - } -} diff --git a/api/src/main/java/io/minio/messages/ReplicationRule.java b/api/src/main/java/io/minio/messages/ReplicationRule.java deleted file mode 100644 index 75993da97..000000000 --- a/api/src/main/java/io/minio/messages/ReplicationRule.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; - -/** Helper class to denote Rule information for {@link ReplicationConfiguration}. */ -@Root(name = "Rule") -public class ReplicationRule { - @Element(name = "DeleteMarkerReplication", required = false) - private DeleteMarkerReplication deleteMarkerReplication; - - @Element(name = "Destination") - private ReplicationDestination destination; - - @Element(name = "ExistingObjectReplication", required = false) - private ExistingObjectReplication existingObjectReplication; - - @Element(name = "Filter", required = false) - private RuleFilter filter; - - @Element(name = "ID", required = false) - private String id; - - @Element(name = "Prefix", required = false) - @Convert(PrefixConverter.class) - private String prefix; - - @Element(name = "Priority", required = false) - private Integer priority; - - @Element(name = "SourceSelectionCriteria", required = false) - private SourceSelectionCriteria sourceSelectionCriteria; - - @Element(name = "DeleteReplication", required = false) - private DeleteReplication deleteReplication; // This is MinIO specific extension. - - @Element(name = "Status") - private Status status; - - /** Constructs new server-side encryption configuration rule. */ - public ReplicationRule( - @Nullable @Element(name = "DeleteMarkerReplication", required = false) - DeleteMarkerReplication deleteMarkerReplication, - @Nonnull @Element(name = "Destination") ReplicationDestination destination, - @Nullable @Element(name = "ExistingObjectReplication", required = false) - ExistingObjectReplication existingObjectReplication, - @Nullable @Element(name = "Filter", required = false) RuleFilter filter, - @Nullable @Element(name = "ID", required = false) String id, - @Nullable @Element(name = "Prefix", required = false) String prefix, - @Nullable @Element(name = "Priority", required = false) Integer priority, - @Nullable @Element(name = "SourceSelectionCriteria", required = false) - SourceSelectionCriteria sourceSelectionCriteria, - @Nullable @Element(name = "DeleteReplication", required = false) - DeleteReplication deleteReplication, - @Nonnull @Element(name = "Status") Status status) { - - if (filter != null && deleteMarkerReplication == null) { - deleteMarkerReplication = new DeleteMarkerReplication(null); - } - - if (id != null) { - id = id.trim(); - if (id.isEmpty()) throw new IllegalArgumentException("ID must be non-empty string"); - if (id.length() > 255) throw new IllegalArgumentException("ID must be exceed 255 characters"); - } - - this.deleteMarkerReplication = deleteMarkerReplication; - this.destination = Objects.requireNonNull(destination, "Destination must not be null"); - this.existingObjectReplication = existingObjectReplication; - this.filter = filter; - this.id = id; - this.prefix = prefix; - this.priority = priority; - this.sourceSelectionCriteria = sourceSelectionCriteria; - this.deleteReplication = deleteReplication; - this.status = Objects.requireNonNull(status, "Status must not be null"); - } - - /** Constructs new server-side encryption configuration rule. */ - public ReplicationRule( - @Nullable @Element(name = "DeleteMarkerReplication", required = false) - DeleteMarkerReplication deleteMarkerReplication, - @Nonnull @Element(name = "Destination") ReplicationDestination destination, - @Nullable @Element(name = "ExistingObjectReplication", required = false) - ExistingObjectReplication existingObjectReplication, - @Nullable @Element(name = "Filter", required = false) RuleFilter filter, - @Nullable @Element(name = "ID", required = false) String id, - @Nullable @Element(name = "Prefix", required = false) String prefix, - @Nullable @Element(name = "Priority", required = false) Integer priority, - @Nullable @Element(name = "SourceSelectionCriteria", required = false) - SourceSelectionCriteria sourceSelectionCriteria, - @Nonnull @Element(name = "Status") Status status) { - this( - deleteMarkerReplication, - destination, - existingObjectReplication, - filter, - id, - prefix, - priority, - sourceSelectionCriteria, - null, - status); - } - - public DeleteMarkerReplication deleteMarkerReplication() { - return this.deleteMarkerReplication; - } - - public ReplicationDestination destination() { - return this.destination; - } - - public ExistingObjectReplication existingObjectReplication() { - return this.existingObjectReplication; - } - - public RuleFilter filter() { - return this.filter; - } - - public String id() { - return this.id; - } - - public String prefix() { - return this.prefix; - } - - public Integer priority() { - return this.priority; - } - - public SourceSelectionCriteria sourceSelectionCriteria() { - return this.sourceSelectionCriteria; - } - - public DeleteReplication deleteReplication() { - return this.deleteReplication; - } - - public Status status() { - return this.status; - } -} diff --git a/api/src/main/java/io/minio/messages/ReplicationTime.java b/api/src/main/java/io/minio/messages/ReplicationTime.java deleted file mode 100644 index 9ba40cadb..000000000 --- a/api/src/main/java/io/minio/messages/ReplicationTime.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote replication time information for {@link ReplicationDestination}. */ -@Root(name = "ReplicationTime") -public class ReplicationTime { - @Element(name = "Time") - private ReplicationTimeValue time; - - @Element(name = "Status") - private Status status; - - public ReplicationTime( - @Nonnull @Element(name = "Time") ReplicationTimeValue time, - @Nonnull @Element(name = "Status") Status status) { - this.time = Objects.requireNonNull(time, "Time must not be null"); - this.status = Objects.requireNonNull(status, "Status must not be null"); - } - - public ReplicationTimeValue time() { - return this.time; - } - - public Status status() { - return this.status; - } -} diff --git a/api/src/main/java/io/minio/messages/ReplicationTimeValue.java b/api/src/main/java/io/minio/messages/ReplicationTimeValue.java deleted file mode 100644 index 41886278c..000000000 --- a/api/src/main/java/io/minio/messages/ReplicationTimeValue.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote replication time value information for {@link Metrics}. */ -@Root(name = "ReplicationTimeValue") -public class ReplicationTimeValue { - @Element(name = "Minutes", required = false) - private Integer minutes = 15; - - public ReplicationTimeValue( - @Nullable @Element(name = "Minutes", required = false) Integer minutes) { - this.minutes = minutes; - } - - public Integer minutes() { - return this.minutes; - } -} diff --git a/api/src/main/java/io/minio/messages/RequestProgress.java b/api/src/main/java/io/minio/messages/RequestProgress.java deleted file mode 100644 index 1f3eb9c7c..000000000 --- a/api/src/main/java/io/minio/messages/RequestProgress.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote progress request in select object content request XML for {@link - * SelectObjectContentRequest}. - */ -@Root(name = "RequestProgress", strict = false) -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class RequestProgress { - @Element(name = "Enabled") - private boolean enabled = true; - - /** Constructs a new RequestProgress object. */ - public RequestProgress() {} -} diff --git a/api/src/main/java/io/minio/messages/ResponseDate.java b/api/src/main/java/io/minio/messages/ResponseDate.java deleted file mode 100644 index 9e3f426ac..000000000 --- a/api/src/main/java/io/minio/messages/ResponseDate.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonCreator; -import io.minio.Time; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.util.Locale; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; -import org.simpleframework.xml.convert.Converter; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.OutputNode; - -/** S3 specified response time wrapping {@link ZonedDateTime}. */ -@Root -@Convert(ResponseDate.ResponseDateConverter.class) -public class ResponseDate { - public static final DateTimeFormatter MINIO_RESPONSE_DATE_FORMAT = - DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH':'mm':'ss'Z'", Locale.US).withZone(Time.UTC); - - private ZonedDateTime zonedDateTime; - - public ResponseDate() {} - - public ResponseDate(ZonedDateTime zonedDateTime) { - this.zonedDateTime = zonedDateTime; - } - - public ZonedDateTime zonedDateTime() { - return zonedDateTime; - } - - public String toString() { - return zonedDateTime.format(Time.RESPONSE_DATE_FORMAT); - } - - @JsonCreator - public static ResponseDate fromString(String responseDateString) { - try { - return new ResponseDate(ZonedDateTime.parse(responseDateString, Time.RESPONSE_DATE_FORMAT)); - } catch (DateTimeParseException e) { - return new ResponseDate(ZonedDateTime.parse(responseDateString, MINIO_RESPONSE_DATE_FORMAT)); - } - } - - /** XML converter class. */ - public static class ResponseDateConverter implements Converter { - @Override - public ResponseDate read(InputNode node) throws Exception { - return ResponseDate.fromString(node.getValue()); - } - - @Override - public void write(OutputNode node, ResponseDate amzDate) { - node.setValue(amzDate.toString()); - } - } -} diff --git a/api/src/main/java/io/minio/messages/RestoreRequest.java b/api/src/main/java/io/minio/messages/RestoreRequest.java index a7718604e..8e364528a 100644 --- a/api/src/main/java/io/minio/messages/RestoreRequest.java +++ b/api/src/main/java/io/minio/messages/RestoreRequest.java @@ -16,13 +16,23 @@ package io.minio.messages; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.minio.Utils; +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.simpleframework.xml.Element; +import org.simpleframework.xml.ElementMap; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; +import org.simpleframework.xml.convert.Convert; +import org.simpleframework.xml.convert.Converter; +import org.simpleframework.xml.stream.InputNode; +import org.simpleframework.xml.stream.OutputNode; /** - * Object representation of request XML of RestoreObject * API. */ @@ -67,4 +77,227 @@ public RestoreRequest( this.selectParameters = selectParameters; this.outputLocation = outputLocation; } + + /** Tier type of {@link RestoreRequest}. */ + @Root(name = "Tier") + @Convert(Tier.TierConverter.class) + public static enum Tier { + STANDARD("Standard"), + BULK("Bulk"), + EXPEDITED("Expedited"); + + private final String value; + + private Tier(String value) { + this.value = value; + } + + public String toString() { + return this.value; + } + + /** Returns Tier of given string. */ + @JsonCreator + public static Tier fromString(String tierString) { + for (Tier tier : Tier.values()) { + if (tierString.equals(tier.value)) { + return tier; + } + } + + throw new IllegalArgumentException("Unknown tier '" + tierString + "'"); + } + + /** XML converter of {@link Tier}. */ + public static class TierConverter implements Converter { + @Override + public Tier read(InputNode node) throws Exception { + return Tier.fromString(node.getValue()); + } + + @Override + public void write(OutputNode node, Tier tier) throws Exception { + node.setValue(tier.toString()); + } + } + } + + /** Glacier job parameters information of {@link RestoreRequest}. */ + @Root(name = "GlacierJobParameters") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class GlacierJobParameters { + @Element(name = "Tier") + private Tier tier; + + public GlacierJobParameters(@Nonnull Tier tier) { + this.tier = Objects.requireNonNull(tier, "Tier must not be null"); + } + } + + /** Select parameters information of {@link RestoreRequest}. */ + @Root(name = "SelectParameters") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class SelectParameters extends BaseSelectParameters { + public SelectParameters( + @Nonnull String expression, + @Nonnull InputSerialization is, + @Nonnull OutputSerialization os) { + super(expression, is, os); + } + } + + /** Output location information of {@link RestoreRequest}. */ + @Root(name = "OutputLocation") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class OutputLocation { + @Element(name = "S3") + private S3 s3; + + public OutputLocation(@Nonnull S3 s3) { + this.s3 = Objects.requireNonNull(s3, "S3 must not be null"); + } + } + + /** S3 information of {@link RestoreRequest.OutputLocation}. */ + @Root(name = "S3") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class S3 { + @Element(name = "AccessControlList", required = false) + private AccessControlList accessControlList; + + @Element(name = "BucketName") + private String bucketName; + + @Element(name = "CannedACL", required = false) + private CannedAcl cannedAcl; + + @Element(name = "Encryption", required = false) + private Encryption encryption; + + @Element(name = "Prefix") + private String prefix; + + @Element(name = "StorageClass", required = false) + private String storageClass; + + @Element(name = "Tagging", required = false) + private Tags tagging; + + @Element(name = "UserMetadata", required = false) + private UserMetadata userMetadata; + + public S3( + @Nonnull String bucketName, + @Nonnull String prefix, + @Nullable AccessControlList accessControlList, + @Nullable CannedAcl cannedAcl, + @Nullable Encryption encryption, + @Nullable String storageClass, + @Nullable Tags tagging, + @Nullable UserMetadata userMetadata) { + this.bucketName = Objects.requireNonNull(bucketName, "Bucket name must not be null"); + this.prefix = Objects.requireNonNull(prefix, "Prefix must not be null"); + this.accessControlList = accessControlList; + this.cannedAcl = cannedAcl; + this.encryption = encryption; + this.storageClass = storageClass; + this.tagging = tagging; + this.userMetadata = userMetadata; + } + } + + /** Canned ACL type of {@link RestoreRequest.S3}. */ + @Root(name = "CannedAcl") + @Convert(CannedAcl.CannedAclConverter.class) + public static enum CannedAcl { + PRIVATE("private"), + PUBLIC_READ("public-read"), + PUBLIC_READ_WRITE("public-read-write"), + AUTHENTICATED_READ("authenticated-read"), + AWS_EXEC_READ("aws-exec-read"), + BUCKET_OWNER_READ("bucket-owner-read"), + BUCKET_OWNER_FULL_CONTROL("bucket-owner-full-control"); + + private final String value; + + private CannedAcl(String value) { + this.value = value; + } + + public String toString() { + return this.value; + } + + /** Returns CannedAcl of given string. */ + @JsonCreator + public static CannedAcl fromString(String cannedAclString) { + for (CannedAcl cannedAcl : CannedAcl.values()) { + if (cannedAclString.equals(cannedAcl.value)) { + return cannedAcl; + } + } + + throw new IllegalArgumentException("Unknown canned ACL '" + cannedAclString + "'"); + } + + /** XML converter of {@link CannedAcl}. */ + public static class CannedAclConverter implements Converter { + @Override + public CannedAcl read(InputNode node) throws Exception { + return CannedAcl.fromString(node.getValue()); + } + + @Override + public void write(OutputNode node, CannedAcl cannedAcl) throws Exception { + node.setValue(cannedAcl.toString()); + } + } + } + + /** Encryption information of {@link RestoreRequest.S3}. */ + @Root(name = "Encryption") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class Encryption { + @Element(name = "EncryptionType") + private SseAlgorithm encryptionType; + + @Element(name = "KMSContext", required = false) + private String kmsContext; + + @Element(name = "KMSKeyId", required = false) + private String kmsKeyId; + + public Encryption( + @Nonnull SseAlgorithm encryptionType, + @Nullable String kmsContext, + @Nullable String kmsKeyId) { + this.encryptionType = + Objects.requireNonNull(encryptionType, "Encryption type must not be null"); + this.kmsContext = kmsContext; + this.kmsKeyId = kmsKeyId; + } + } + + /** User metadata information of {@link RestoreRequest.S3}. */ + @Root(name = "UserMetadata", strict = false) + @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class UserMetadata { + @ElementMap( + attribute = false, + entry = "MetadataEntry", + inline = true, + key = "Name", + value = "Value", + required = false) + Map metadataEntries; + + private UserMetadata(@Nonnull Map metadataEntries) { + Objects.requireNonNull(metadataEntries, "Metadata entries must not be null"); + if (metadataEntries.size() == 0) { + throw new IllegalArgumentException("Metadata entries must not be empty"); + } + this.metadataEntries = Utils.unmodifiableMap(metadataEntries); + } + } } diff --git a/api/src/main/java/io/minio/messages/Retention.java b/api/src/main/java/io/minio/messages/Retention.java index ade0cd21a..4fb7eb46a 100644 --- a/api/src/main/java/io/minio/messages/Retention.java +++ b/api/src/main/java/io/minio/messages/Retention.java @@ -16,13 +16,15 @@ package io.minio.messages; +import io.minio.Time; +import io.minio.Utils; import java.time.ZonedDateTime; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutObjectRetention * API and response XML of GetObjectRetention @@ -35,7 +37,7 @@ public class Retention { private RetentionMode mode; @Element(name = "RetainUntilDate", required = false) - private ResponseDate retainUntilDate; + private Time.S3Time retainUntilDate; public Retention() {} @@ -50,7 +52,7 @@ public Retention(RetentionMode mode, ZonedDateTime retainUntilDate) { } this.mode = mode; - this.retainUntilDate = new ResponseDate(retainUntilDate); + this.retainUntilDate = new Time.S3Time(retainUntilDate); } /** Returns mode. */ @@ -60,10 +62,13 @@ public RetentionMode mode() { /** Returns retain until date. */ public ZonedDateTime retainUntilDate() { - if (retainUntilDate != null) { - return retainUntilDate.zonedDateTime(); - } + return retainUntilDate == null ? null : retainUntilDate.toZonedDateTime(); + } - return null; + @Override + public String toString() { + return String.format( + "Retention{mode=%s, retainUntilDate=%s}", + Utils.stringify(mode), Utils.stringify(retainUntilDate)); } } diff --git a/api/src/main/java/io/minio/messages/RetentionDuration.java b/api/src/main/java/io/minio/messages/RetentionDuration.java deleted file mode 100644 index 7550dbbd2..000000000 --- a/api/src/main/java/io/minio/messages/RetentionDuration.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -/** Retention duration of {@link ObjectLockConfiguration} */ -public interface RetentionDuration { - public RetentionDurationUnit unit(); - - public int duration(); -} diff --git a/api/src/main/java/io/minio/messages/RetentionDurationDays.java b/api/src/main/java/io/minio/messages/RetentionDurationDays.java deleted file mode 100644 index ad0eaa5ad..000000000 --- a/api/src/main/java/io/minio/messages/RetentionDurationDays.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Root; -import org.simpleframework.xml.Text; - -/** Days type retention duration of {@link ObjectLockConfiguration} */ -@Root(name = "Days") -public class RetentionDurationDays implements RetentionDuration { - @Text(required = false) - private Integer days; - - public RetentionDurationDays() {} - - public RetentionDurationDays(int days) { - this.days = Integer.valueOf(days); - } - - public RetentionDurationUnit unit() { - return RetentionDurationUnit.DAYS; - } - - public int duration() { - return days; - } - - /** Returns RetentionDurationDays as string. */ - @Override - public String toString() { - if (days == null) { - return ""; - } - return days.toString() + ((days == 1) ? " day" : " days"); - } -} diff --git a/api/src/main/java/io/minio/messages/RetentionDurationUnit.java b/api/src/main/java/io/minio/messages/RetentionDurationUnit.java deleted file mode 100644 index 22823805d..000000000 --- a/api/src/main/java/io/minio/messages/RetentionDurationUnit.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -/** Duration unit of default retention configuration. */ -public enum RetentionDurationUnit { - DAYS, - YEARS; -} diff --git a/api/src/main/java/io/minio/messages/RetentionDurationYears.java b/api/src/main/java/io/minio/messages/RetentionDurationYears.java deleted file mode 100644 index 50b75e663..000000000 --- a/api/src/main/java/io/minio/messages/RetentionDurationYears.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Root; -import org.simpleframework.xml.Text; - -/** Years type retention duration of {@link ObjectLockConfiguration} */ -@Root(name = "Years") -public class RetentionDurationYears implements RetentionDuration { - @Text(required = false) - private Integer years; - - public RetentionDurationYears() {} - - public RetentionDurationYears(int years) { - this.years = Integer.valueOf(years); - } - - public RetentionDurationUnit unit() { - return RetentionDurationUnit.YEARS; - } - - public int duration() { - return years; - } - - /** Returns RetentionDurationYears as string. */ - @Override - public String toString() { - if (years == null) { - return ""; - } - return years.toString() + ((years == 1) ? " year" : " years"); - } -} diff --git a/api/src/main/java/io/minio/messages/Rule.java b/api/src/main/java/io/minio/messages/Rule.java deleted file mode 100644 index 65cf0c829..000000000 --- a/api/src/main/java/io/minio/messages/Rule.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.ElementUnion; -import org.simpleframework.xml.Path; -import org.simpleframework.xml.Root; - -/** Helper class to denote Rule information for {@link ObjectLockConfiguration}. */ -@Root(name = "Rule", strict = false) -public class Rule { - @Path(value = "DefaultRetention") - @Element(name = "Mode", required = false) - private RetentionMode mode; - - @Path(value = "DefaultRetention") - @ElementUnion({ - @Element(name = "Days", type = RetentionDurationDays.class, required = false), - @Element(name = "Years", type = RetentionDurationYears.class, required = false) - }) - private RetentionDuration duration; - - public Rule( - @Element(name = "Mode", required = false) RetentionMode mode, - @ElementUnion({ - @Element(name = "Days", type = RetentionDurationDays.class, required = false), - @Element(name = "Years", type = RetentionDurationYears.class, required = false) - }) - RetentionDuration duration) { - if (mode != null && duration != null) { - this.mode = mode; - this.duration = duration; - } else if (mode != null || duration != null) { - if (mode == null) { - throw new IllegalArgumentException("mode is null"); - } - throw new IllegalArgumentException("duration is null"); - } - } - - public RetentionMode mode() { - return mode; - } - - public RetentionDuration duration() { - return duration; - } -} diff --git a/api/src/main/java/io/minio/messages/RuleFilter.java b/api/src/main/java/io/minio/messages/RuleFilter.java deleted file mode 100644 index c5da2464a..000000000 --- a/api/src/main/java/io/minio/messages/RuleFilter.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; - -/** - * Helper class to denote filter information for {@link ReplicationRule} and {@link LifecycleRule}. - */ -@Root(name = "Filter") -public class RuleFilter { - @Element(name = "And", required = false) - private AndOperator andOperator; - - @Element(name = "Prefix", required = false) - @Convert(PrefixConverter.class) - private String prefix; - - @Element(name = "Tag", required = false) - private Tag tag; - - @Element(name = "ObjectSizeLessThan", required = false) - private Long objectSizeLessThan; - - @Element(name = "ObjectSizeGreaterThan", required = false) - private Long objectSizeGreaterThan; - - public RuleFilter( - @Nullable @Element(name = "And", required = false) AndOperator andOperator, - @Nullable @Element(name = "Prefix", required = false) String prefix, - @Nullable @Element(name = "Tag", required = false) Tag tag) { - if (andOperator != null ^ prefix != null ^ tag != null) { - this.andOperator = andOperator; - this.prefix = prefix; - this.tag = tag; - } else { - throw new IllegalArgumentException("Only one of And, Prefix or Tag must be set"); - } - } - - public RuleFilter( - @Nullable @Element(name = "And", required = false) AndOperator andOperator, - @Nullable @Element(name = "Prefix", required = false) String prefix, - @Nullable @Element(name = "Tag", required = false) Tag tag, - @Nullable @Element(name = "ObjectSizeLessThan", required = false) Long objectSizeLessThan, - @Nullable @Element(name = "ObjectSizeGreaterThan", required = false) - Long objectSizeGreaterThan) { - this(andOperator, prefix, tag); - this.objectSizeLessThan = objectSizeLessThan; - this.objectSizeGreaterThan = objectSizeGreaterThan; - } - - public RuleFilter(@Nonnull AndOperator andOperator) { - this.andOperator = Objects.requireNonNull(andOperator, "And operator must not be null"); - } - - public RuleFilter(@Nonnull String prefix) { - this.prefix = Objects.requireNonNull(prefix, "Prefix must not be null"); - } - - public RuleFilter(@Nonnull Tag tag) { - this.tag = Objects.requireNonNull(tag, "Tag must not be null"); - } - - public AndOperator andOperator() { - return this.andOperator; - } - - public String prefix() { - return this.prefix; - } - - public Tag tag() { - return this.tag; - } - - public Long objectSizeLessThan() { - return this.objectSizeLessThan; - } - - public Long objectSizeGreaterThan() { - return this.objectSizeGreaterThan; - } -} diff --git a/api/src/main/java/io/minio/messages/S3OutputLocation.java b/api/src/main/java/io/minio/messages/S3OutputLocation.java deleted file mode 100644 index 17c0237c7..000000000 --- a/api/src/main/java/io/minio/messages/S3OutputLocation.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote S3 output location information of {@link OutputLocation}. */ -@Root(name = "S3OutputLocation") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class S3OutputLocation { - @Element(name = "AccessControlList", required = false) - private AccessControlList accessControlList; - - @Element(name = "BucketName") - private String bucketName; - - @Element(name = "CannedACL", required = false) - private CannedAcl cannedAcl; - - @Element(name = "Encryption", required = false) - private Encryption encryption; - - @Element(name = "Prefix") - private String prefix; - - @Element(name = "StorageClass", required = false) - private String storageClass; - - @Element(name = "Tagging", required = false) - private Tags tagging; - - @Element(name = "UserMetadata", required = false) - private UserMetadata userMetadata; - - public S3OutputLocation( - @Nonnull String bucketName, - @Nonnull String prefix, - @Nullable AccessControlList accessControlList, - @Nullable CannedAcl cannedAcl, - @Nullable Encryption encryption, - @Nullable String storageClass, - @Nullable Tags tagging, - @Nullable UserMetadata userMetadata) { - this.bucketName = Objects.requireNonNull(bucketName, "Bucket name must not be null"); - this.prefix = Objects.requireNonNull(prefix, "Prefix must not be null"); - this.accessControlList = accessControlList; - this.cannedAcl = cannedAcl; - this.encryption = encryption; - this.storageClass = storageClass; - this.tagging = tagging; - this.userMetadata = userMetadata; - } -} diff --git a/api/src/main/java/io/minio/messages/ScanRange.java b/api/src/main/java/io/minio/messages/ScanRange.java deleted file mode 100644 index 8e2c8b7dd..000000000 --- a/api/src/main/java/io/minio/messages/ScanRange.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2019 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote scan range in select object content request XML for {@link - * SelectObjectContentRequest}. - */ -@Root(name = "ScanRange") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class ScanRange { - @Element(name = "Start", required = false) - private Long start; - - @Element(name = "End", required = false) - private Long end; - - /** Constructs new ScanRange object for given start and end. */ - public ScanRange(Long start, Long end) { - this.start = start; - this.end = end; - } -} diff --git a/api/src/main/java/io/minio/messages/SelectObjectContentRequest.java b/api/src/main/java/io/minio/messages/SelectObjectContentRequest.java index 59641837b..fa0f1134a 100644 --- a/api/src/main/java/io/minio/messages/SelectObjectContentRequest.java +++ b/api/src/main/java/io/minio/messages/SelectObjectContentRequest.java @@ -23,21 +23,20 @@ import org.simpleframework.xml.Root; /** - * Object representation of request XML of SelectObjectContent * API. */ @Root(name = "SelectObjectContentRequest") @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class SelectObjectContentRequest extends SelectObjectContentRequestBase { +public class SelectObjectContentRequest extends BaseSelectParameters { @Element(name = "RequestProgress", required = false) private RequestProgress requestProgress; @Element(name = "ScanRange", required = false) private ScanRange scanRange; - /** Constructs new SelectObjectContentRequest object for given parameters. */ public SelectObjectContentRequest( @Nonnull String expression, boolean requestProgress, @@ -53,4 +52,30 @@ public SelectObjectContentRequest( this.scanRange = new ScanRange(scanStartRange, scanEndRange); } } + + /** Request progress information of {@link SelectObjectContentRequest}. */ + @Root(name = "RequestProgress", strict = false) + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class RequestProgress { + @Element(name = "Enabled") + private boolean enabled = true; + + public RequestProgress() {} + } + + /** Scan range information of {@link SelectObjectContentRequest}. */ + @Root(name = "ScanRange") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class ScanRange { + @Element(name = "Start", required = false) + private Long start; + + @Element(name = "End", required = false) + private Long end; + + public ScanRange(Long start, Long end) { + this.start = start; + this.end = end; + } + } } diff --git a/api/src/main/java/io/minio/messages/SelectParameters.java b/api/src/main/java/io/minio/messages/SelectParameters.java deleted file mode 100644 index cf8326ab9..000000000 --- a/api/src/main/java/io/minio/messages/SelectParameters.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import javax.annotation.Nonnull; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote the parameters for Select job types information of {@link RestoreRequest}. - */ -@Root(name = "SelectParameters") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class SelectParameters extends SelectObjectContentRequestBase { - public SelectParameters( - @Nonnull String expression, @Nonnull InputSerialization is, @Nonnull OutputSerialization os) { - super(expression, is, os); - } -} diff --git a/api/src/main/java/io/minio/messages/Source.java b/api/src/main/java/io/minio/messages/Source.java deleted file mode 100644 index fe5896e4c..000000000 --- a/api/src/main/java/io/minio/messages/Source.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2020 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Helper class to denote client information causes this event. This is MinIO extension to Event - * Message Structure - */ -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( - value = "UwF", - justification = "Everything in this class is initialized by JSON unmarshalling.") -public class Source { - @JsonProperty private String host; - @JsonProperty private String port; - @JsonProperty private String userAgent; - - public String host() { - return host; - } - - public String port() { - return port; - } - - public String userAgent() { - return userAgent; - } -} diff --git a/api/src/main/java/io/minio/messages/SourceSelectionCriteria.java b/api/src/main/java/io/minio/messages/SourceSelectionCriteria.java deleted file mode 100644 index 542fc9617..000000000 --- a/api/src/main/java/io/minio/messages/SourceSelectionCriteria.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote source selection criteria information for {@link ReplicationRule}. */ -@Root(name = "SourceSelectionCriteria") -public class SourceSelectionCriteria { - @Element(name = "ReplicaModifications", required = false) - private ReplicaModifications replicaModifications; - - @Element(name = "SseKmsEncryptedObjects", required = false) - private SseKmsEncryptedObjects sseKmsEncryptedObjects; - - public SourceSelectionCriteria( - @Nullable @Element(name = "SseKmsEncryptedObjects", required = false) - SseKmsEncryptedObjects sseKmsEncryptedObjects, - @Nullable @Element(name = "ReplicaModifications", required = false) - ReplicaModifications replicaModifications) { - this.sseKmsEncryptedObjects = sseKmsEncryptedObjects; - this.replicaModifications = replicaModifications; - } - - public SourceSelectionCriteria(@Nullable SseKmsEncryptedObjects sseKmsEncryptedObjects) { - this(sseKmsEncryptedObjects, null); - } - - public ReplicaModifications replicaModifications() { - return this.replicaModifications; - } - - public SseKmsEncryptedObjects sseKmsEncryptedObjects() { - return this.sseKmsEncryptedObjects; - } -} diff --git a/api/src/main/java/io/minio/messages/SseAlgorithm.java b/api/src/main/java/io/minio/messages/SseAlgorithm.java index 811bbbd8e..b42eac3c0 100644 --- a/api/src/main/java/io/minio/messages/SseAlgorithm.java +++ b/api/src/main/java/io/minio/messages/SseAlgorithm.java @@ -23,7 +23,10 @@ import org.simpleframework.xml.stream.InputNode; import org.simpleframework.xml.stream.OutputNode; -/** Server-side encryption algorithm. */ +/** + * Server-side encryption algorithm type of {@link RestoreRequest.Encryption} and {@link + * SseConfiguration.Rule}. + */ @Root(name = "SSEAlgorithm") @Convert(SseAlgorithm.SseAlgorithmConverter.class) public enum SseAlgorithm { @@ -52,7 +55,7 @@ public static SseAlgorithm fromString(String sseAlgorithmString) { throw new IllegalArgumentException("unknown SSE algorithm '" + sseAlgorithmString + "'"); } - /** XML converter class. */ + /** XML converter of {@link SseAlgorithm}. */ public static class SseAlgorithmConverter implements Converter { @Override public SseAlgorithm read(InputNode node) throws Exception { diff --git a/api/src/main/java/io/minio/messages/SseConfiguration.java b/api/src/main/java/io/minio/messages/SseConfiguration.java index 1107be67d..0ab00032c 100644 --- a/api/src/main/java/io/minio/messages/SseConfiguration.java +++ b/api/src/main/java/io/minio/messages/SseConfiguration.java @@ -16,39 +16,84 @@ package io.minio.messages; +import io.minio.Utils; +import java.util.Objects; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; +import org.simpleframework.xml.Path; import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutBucketEncryption * API and response XML of GetBucketEncryption * API. */ -@Root(name = "ServerSideEncryptionConfiguration") +@Root(name = "ServerSideEncryptionConfiguration", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") public class SseConfiguration { @Element(name = "Rule", required = false) - private SseConfigurationRule rule; + private Rule rule; - public SseConfiguration( - @Nullable @Element(name = "Rule", required = false) SseConfigurationRule rule) { + public SseConfiguration(@Nullable @Element(name = "Rule", required = false) Rule rule) { this.rule = rule; } public static SseConfiguration newConfigWithSseS3Rule() { - return new SseConfiguration(new SseConfigurationRule(SseAlgorithm.AES256, null)); + return new SseConfiguration(new Rule(SseAlgorithm.AES256, null)); } public static SseConfiguration newConfigWithSseKmsRule(@Nullable String kmsMasterKeyId) { - return new SseConfiguration(new SseConfigurationRule(SseAlgorithm.AWS_KMS, kmsMasterKeyId)); + return new SseConfiguration(new Rule(SseAlgorithm.AWS_KMS, kmsMasterKeyId)); } - public SseConfigurationRule rule() { + public Rule rule() { return this.rule; } + + @Override + public String toString() { + return String.format("SseConfiguration{rule=%s}", Utils.stringify(rule)); + } + + /** Rule information of {@link SseConfiguration}. */ + @Root(name = "Rule", strict = false) + @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") + public static class Rule { + @Path(value = "ApplyServerSideEncryptionByDefault") + @Element(name = "KMSMasterKeyID", required = false) + private String kmsMasterKeyId; + + @Path(value = "ApplyServerSideEncryptionByDefault") + @Element(name = "SSEAlgorithm") + private SseAlgorithm sseAlgorithm; + + /** Constructs new server-side encryption configuration rule. */ + public Rule( + @Nonnull @Element(name = "SSEAlgorithm") SseAlgorithm sseAlgorithm, + @Nullable @Element(name = "KMSMasterKeyID", required = false) String kmsMasterKeyId) { + this.sseAlgorithm = Objects.requireNonNull(sseAlgorithm, "SSE Algorithm must be provided"); + this.kmsMasterKeyId = kmsMasterKeyId; + } + + public String kmsMasterKeyId() { + return this.kmsMasterKeyId; + } + + public SseAlgorithm sseAlgorithm() { + return this.sseAlgorithm; + } + + @Override + public String toString() { + return String.format( + "Rule{sseAlgorithm=%s, kmsMasterKeyId=%s}", + Utils.stringify(sseAlgorithm), Utils.stringify(kmsMasterKeyId)); + } + } } diff --git a/api/src/main/java/io/minio/messages/SseConfigurationRule.java b/api/src/main/java/io/minio/messages/SseConfigurationRule.java deleted file mode 100644 index ff997a39c..000000000 --- a/api/src/main/java/io/minio/messages/SseConfigurationRule.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Namespace; -import org.simpleframework.xml.Path; -import org.simpleframework.xml.Root; - -/** Helper class to denote Rule information for {@link SseConfiguration}. */ -@Root(name = "Rule") -@Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class SseConfigurationRule { - @Path(value = "ApplyServerSideEncryptionByDefault") - @Element(name = "KMSMasterKeyID", required = false) - private String kmsMasterKeyId; - - @Path(value = "ApplyServerSideEncryptionByDefault") - @Element(name = "SSEAlgorithm") - private SseAlgorithm sseAlgorithm; - - /** Constructs new server-side encryption configuration rule. */ - public SseConfigurationRule( - @Nonnull @Element(name = "SSEAlgorithm") SseAlgorithm sseAlgorithm, - @Nullable @Element(name = "KMSMasterKeyID", required = false) String kmsMasterKeyId) { - this.sseAlgorithm = Objects.requireNonNull(sseAlgorithm, "SSE Algorithm must be provided"); - this.kmsMasterKeyId = kmsMasterKeyId; - } - - public String kmsMasterKeyId() { - return this.kmsMasterKeyId; - } - - public SseAlgorithm sseAlgorithm() { - return this.sseAlgorithm; - } -} diff --git a/api/src/main/java/io/minio/messages/SseKmsEncryptedObjects.java b/api/src/main/java/io/minio/messages/SseKmsEncryptedObjects.java deleted file mode 100644 index 1cdf045eb..000000000 --- a/api/src/main/java/io/minio/messages/SseKmsEncryptedObjects.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote SSE KMS encrypted objects information for {@link SourceSelectionCriteria}. - */ -@Root(name = "SseKmsEncryptedObjects") -public class SseKmsEncryptedObjects { - @Element(name = "Status") - private Status status; - - public SseKmsEncryptedObjects(@Nonnull @Element(name = "Status") Status status) { - this.status = Objects.requireNonNull(status, "Status must not be null"); - } - - public Status status() { - return this.status; - } -} diff --git a/api/src/main/java/io/minio/messages/Stats.java b/api/src/main/java/io/minio/messages/Stats.java index da8471b83..d747ab9d4 100644 --- a/api/src/main/java/io/minio/messages/Stats.java +++ b/api/src/main/java/io/minio/messages/Stats.java @@ -20,34 +20,52 @@ import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; -/** Helper class to denote Stats information of S3 select response message. */ +/** Stats information of S3 select response message. */ @Root(name = "Stats", strict = false) @Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") public class Stats { - @Element(name = "BytesScanned") - private long bytesScanned = -1; + @Element(name = "BytesScanned", required = false) + private Long bytesScanned; - @Element(name = "BytesProcessed") - private long bytesProcessed = -1; + @Element(name = "BytesProcessed", required = false) + private Long bytesProcessed; - @Element(name = "BytesReturned") - private long bytesReturned = -1; + @Element(name = "BytesReturned", required = false) + private Long bytesReturned; /** Constructs a new Stats object. */ - public Stats() {} + public Stats( + @Element(name = "BytesScanned", required = false) Long bytesScanned, + @Element(name = "BytesProcessed", required = false) Long bytesProcessed, + @Element(name = "BytesReturned", required = false) Long bytesReturned) { + this.bytesScanned = bytesScanned; + this.bytesProcessed = bytesProcessed; + this.bytesReturned = bytesReturned; + } /** Returns bytes scanned. */ - public long bytesScanned() { - return this.bytesScanned; + public Long bytesScanned() { + return bytesScanned; } /** Returns bytes processed. */ - public long bytesProcessed() { - return this.bytesProcessed; + public Long bytesProcessed() { + return bytesProcessed; } /** Returns bytes returned. */ - public long bytesReturned() { - return this.bytesReturned; + public Long bytesReturned() { + return bytesReturned; + } + + protected String stringify() { + return String.format( + "bytesScanned=%s, bytesProcessed=%s, bytesReturned=%s", + bytesScanned, bytesProcessed, bytesReturned); + } + + @Override + public String toString() { + return String.format("Stats{%s}", stringify()); } } diff --git a/api/src/main/java/io/minio/messages/Status.java b/api/src/main/java/io/minio/messages/Status.java index 1d1918788..902a4b254 100644 --- a/api/src/main/java/io/minio/messages/Status.java +++ b/api/src/main/java/io/minio/messages/Status.java @@ -23,7 +23,7 @@ import org.simpleframework.xml.stream.InputNode; import org.simpleframework.xml.stream.OutputNode; -/** Status representing Disabled/Enabled. */ +/** Status type of {@link LifecycleConfiguration.Rule} and {@link ReplicationConfiguration.Rule}. */ @Root(name = "Status") @Convert(Status.StatusConverter.class) public enum Status { @@ -52,7 +52,7 @@ public static Status fromString(String statusString) { throw new IllegalArgumentException("Unknown status '" + statusString + "'"); } - /** XML converter class. */ + /** XML converter of {@link Status}. */ public static class StatusConverter implements Converter { @Override public Status read(InputNode node) throws Exception { diff --git a/api/src/main/java/io/minio/messages/Tag.java b/api/src/main/java/io/minio/messages/Tag.java deleted file mode 100644 index 841e38ae9..000000000 --- a/api/src/main/java/io/minio/messages/Tag.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote tag information for {@link RuleFilter}. */ -@Root(name = "Tag") -public class Tag { - @Element(name = "Key") - private String key; - - @Element(name = "Value") - private String value; - - public Tag( - @Nonnull @Element(name = "Key") String key, @Nonnull @Element(name = "Value") String value) { - Objects.requireNonNull(key, "Key must not be null"); - if (key.isEmpty()) { - throw new IllegalArgumentException("Key must not be empty"); - } - - this.key = key; - this.value = Objects.requireNonNull(value, "Value must not be null"); - } - - public String key() { - return this.key; - } - - public String value() { - return this.value; - } -} diff --git a/api/src/main/java/io/minio/messages/Tags.java b/api/src/main/java/io/minio/messages/Tags.java index 1d191c109..4a87e4636 100644 --- a/api/src/main/java/io/minio/messages/Tags.java +++ b/api/src/main/java/io/minio/messages/Tags.java @@ -24,11 +24,11 @@ import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutBucketTagging - * API and , PutObjectTagging - * API response XML of , GetBucketTagging * API and GetObjectTagging @@ -103,4 +103,9 @@ public static Tags newObjectTags(Map tags) throws IllegalArgumen public Map get() { return Utils.unmodifiableMap(tags); } + + @Override + public String toString() { + return String.format("Tags{%s}", Utils.stringify(tags)); + } } diff --git a/api/src/main/java/io/minio/messages/Tier.java b/api/src/main/java/io/minio/messages/Tier.java deleted file mode 100644 index f22df7dee..000000000 --- a/api/src/main/java/io/minio/messages/Tier.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import com.fasterxml.jackson.annotation.JsonCreator; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.convert.Convert; -import org.simpleframework.xml.convert.Converter; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.OutputNode; - -/** Tier representing retrieval tier value. */ -@Root(name = "Tier") -@Convert(Tier.TierConverter.class) -public enum Tier { - STANDARD("Standard"), - BULK("Bulk"), - EXPEDITED("Expedited"); - - private final String value; - - private Tier(String value) { - this.value = value; - } - - public String toString() { - return this.value; - } - - /** Returns Tier of given string. */ - @JsonCreator - public static Tier fromString(String tierString) { - for (Tier tier : Tier.values()) { - if (tierString.equals(tier.value)) { - return tier; - } - } - - throw new IllegalArgumentException("Unknown tier '" + tierString + "'"); - } - - /** XML converter class. */ - public static class TierConverter implements Converter { - @Override - public Tier read(InputNode node) throws Exception { - return Tier.fromString(node.getValue()); - } - - @Override - public void write(OutputNode node, Tier tier) throws Exception { - node.setValue(tier.toString()); - } - } -} diff --git a/api/src/main/java/io/minio/messages/TopicConfiguration.java b/api/src/main/java/io/minio/messages/TopicConfiguration.java deleted file mode 100644 index 6c9a49df0..000000000 --- a/api/src/main/java/io/minio/messages/TopicConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2017 MinIO, 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 io.minio.messages; - -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote Topic configuration of {@link NotificationConfiguration}. */ -@Root(name = "TopicConfiguration", strict = false) -public class TopicConfiguration extends NotificationCommonConfiguration { - @Element(name = "Topic") - private String topic; - - public TopicConfiguration() { - super(); - } - - /** Returns topic. */ - public String topic() { - return topic; - } - - /** Sets topic. */ - public void setTopic(String topic) { - this.topic = topic; - } -} diff --git a/api/src/main/java/io/minio/messages/Transition.java b/api/src/main/java/io/minio/messages/Transition.java deleted file mode 100644 index 483364e45..000000000 --- a/api/src/main/java/io/minio/messages/Transition.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, 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 io.minio.messages; - -import java.time.ZonedDateTime; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; - -/** Helper class to denote transition information for {@link LifecycleRule}. */ -@Root(name = "Transition") -public class Transition extends DateDays { - @Element(name = "StorageClass") - private String storageClass; - - public Transition( - @Nullable @Element(name = "Date", required = false) ResponseDate date, - @Nullable @Element(name = "Days", required = false) Integer days, - @Nonnull @Element(name = "StorageClass", required = false) String storageClass) { - if (date != null ^ days != null) { - this.date = date; - this.days = days; - } else { - throw new IllegalArgumentException("Only one of date or days must be set"); - } - if (storageClass == null || storageClass.isEmpty()) { - throw new IllegalArgumentException("StorageClass must be provided"); - } - this.storageClass = storageClass; - } - - public Transition(ZonedDateTime date, Integer days, String storageClass) { - this(date == null ? null : new ResponseDate(date), days, storageClass); - } - - public String storageClass() { - return storageClass; - } -} diff --git a/api/src/main/java/io/minio/messages/Upload.java b/api/src/main/java/io/minio/messages/Upload.java deleted file mode 100644 index bf9b8a1ed..000000000 --- a/api/src/main/java/io/minio/messages/Upload.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2015 MinIO, 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 io.minio.messages; - -import io.minio.Utils; -import java.time.ZonedDateTime; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Namespace; -import org.simpleframework.xml.Root; - -/** - * Helper class to denote Upload information of a multipart upload and used in {@link - * ListMultipartUploadsResult}. - */ -@Root(name = "Upload", strict = false) -@Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -public class Upload { - @Element(name = "Key") - private String objectName; - - @Element(name = "UploadId") - private String uploadId; - - @Element(name = "Initiator") - private Initiator initiator; - - @Element(name = "Owner") - private Owner owner; - - @Element(name = "StorageClass") - private String storageClass; - - @Element(name = "Initiated") - private ResponseDate initiated; - - @Element(name = "ChecksumAlgorithm", required = false) - private String checksumAlgorithm; - - @Element(name = "ChecksumType", required = false) - private String checksumType; - - private long aggregatedPartSize; - private String encodingType = null; - - public Upload() {} - - /** Returns object name. */ - public String objectName() { - return Utils.urlDecode(objectName, encodingType); - } - - /** Returns upload ID. */ - public String uploadId() { - return uploadId; - } - - /** Returns initator information. */ - public Initiator initiator() { - return initiator; - } - - /** Returns owner information. */ - public Owner owner() { - return owner; - } - - /** Returns storage class. */ - public String storageClass() { - return storageClass; - } - - /** Returns initated time. */ - public ZonedDateTime initiated() { - return initiated.zonedDateTime(); - } - - /** Returns aggregated part size. */ - public long aggregatedPartSize() { - return aggregatedPartSize; - } - - /** Sets given aggregated part size. */ - public void setAggregatedPartSize(long size) { - this.aggregatedPartSize = size; - } - - public void setEncodingType(String encodingType) { - this.encodingType = encodingType; - } - - public String checksumAlgorithm() { - return checksumAlgorithm; - } - - public String checksumType() { - return checksumType; - } -} diff --git a/api/src/main/java/io/minio/messages/UserMetadata.java b/api/src/main/java/io/minio/messages/UserMetadata.java deleted file mode 100644 index 727e2b3fc..000000000 --- a/api/src/main/java/io/minio/messages/UserMetadata.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, 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 io.minio.messages; - -import io.minio.Utils; -import java.util.Map; -import java.util.Objects; -import javax.annotation.Nonnull; -import org.simpleframework.xml.ElementMap; -import org.simpleframework.xml.Namespace; -import org.simpleframework.xml.Root; - -/** Helper class to denote user metadata information of {@link S3OutputLocation}. */ -@Root(name = "UserMetadata", strict = false) -@Namespace(reference = "http://s3.amazonaws.com/doc/2006-03-01/") -@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "URF_UNREAD_FIELD") -public class UserMetadata { - @ElementMap( - attribute = false, - entry = "MetadataEntry", - inline = true, - key = "Name", - value = "Value", - required = false) - Map metadataEntries; - - private UserMetadata(@Nonnull Map metadataEntries) { - Objects.requireNonNull(metadataEntries, "Metadata entries must not be null"); - if (metadataEntries.size() == 0) { - throw new IllegalArgumentException("Metadata entries must not be empty"); - } - this.metadataEntries = Utils.unmodifiableMap(metadataEntries); - } -} diff --git a/api/src/main/java/io/minio/messages/VersioningConfiguration.java b/api/src/main/java/io/minio/messages/VersioningConfiguration.java index d67536586..665e8ef70 100644 --- a/api/src/main/java/io/minio/messages/VersioningConfiguration.java +++ b/api/src/main/java/io/minio/messages/VersioningConfiguration.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -24,7 +25,7 @@ import org.simpleframework.xml.Root; /** - * Object representation of request XML of PutBucketVersioning * API and response XML of GetBucketVersioning @@ -63,6 +64,13 @@ public Boolean isMfaDeleteEnabled() { return flag; } + @Override + public String toString() { + return String.format( + "VersioningConfiguration{status=%s, mfaDelete=%s}", + Utils.stringify(status), Utils.stringify(mfaDelete)); + } + public static enum Status { OFF(""), ENABLED("Enabled"), diff --git a/api/src/main/java/io/minio/org/apache/commons/validator/routines/InetAddressValidator.java b/api/src/main/java/io/minio/org/apache/commons/validator/routines/InetAddressValidator.java deleted file mode 100644 index 5101f593b..000000000 --- a/api/src/main/java/io/minio/org/apache/commons/validator/routines/InetAddressValidator.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 io.minio.org.apache.commons.validator.routines; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * InetAddress validation and conversion routines (java.net.InetAddress). - * - *

- * - *

- * - *

This class provides methods to validate a candidate IP address. - * - *

- * - *

This class is a Singleton; you can retrieve the instance via the {@link #getInstance()} - * method. - * - * @version $Revision$ - * @since Validator 1.4 - */ -public class InetAddressValidator { - - private static final int IPV4_MAX_OCTET_VALUE = 255; - - private static final int MAX_UNSIGNED_SHORT = 0xffff; - - private static final int BASE_16 = 16; - - private static final long serialVersionUID = -919201640201914789L; - - private static final String IPV4_REGEX = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"; - - // Max number of hex groups (separated by :) in an IPV6 address - private static final int IPV6_MAX_HEX_GROUPS = 8; - - // Max hex digits in each IPv6 group - private static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4; - - /** Singleton instance of this class. */ - private static final InetAddressValidator VALIDATOR = new InetAddressValidator(); - - /** IPv4 RegexValidator. */ - private final RegexValidator ipv4Validator = new RegexValidator(IPV4_REGEX); - - private InetAddressValidator() {} - - /** - * Returns the singleton instance of this validator. - * - * @return the singleton instance of this validator - */ - public static InetAddressValidator getInstance() { - return VALIDATOR; - } - - /** - * Checks if the specified string is a valid IP address. - * - * @param inetAddress the string to validate - * @return true if the string validates as an IP address - */ - public boolean isValid(String inetAddress) { - return isValidInet4Address(inetAddress) || isValidInet6Address(inetAddress); - } - - /** - * Validates an IPv4 address. Returns true if valid. - * - * @param inet4Address the IPv4 address to validate - * @return true if the argument contains a valid IPv4 address - */ - public boolean isValidInet4Address(String inet4Address) { - // verify that address conforms to generic IPv4 format - String[] groups = ipv4Validator.match(inet4Address); - - if (groups == null) { - return false; - } - - // verify that address subgroups are legal - for (String ipSegment : groups) { - if (ipSegment == null || ipSegment.length() == 0) { - return false; - } - - int iIpSegment = 0; - - try { - iIpSegment = Integer.parseInt(ipSegment); - } catch (NumberFormatException e) { - return false; - } - - if (iIpSegment > IPV4_MAX_OCTET_VALUE) { - return false; - } - - if (ipSegment.length() > 1 && ipSegment.startsWith("0")) { - return false; - } - } - - return true; - } - - /** - * Validates an IPv6 address. Returns true if valid. - * - * @param inet6Address the IPv6 address to validate - * @return true if the argument contains a valid IPv6 address - * @since 1.4.1 - */ - public boolean isValidInet6Address(String inet6Address) { - boolean containsCompressedZeroes = inet6Address.contains("::"); - if (containsCompressedZeroes && inet6Address.indexOf("::") != inet6Address.lastIndexOf("::")) { - return false; - } - if (inet6Address.startsWith(":") && !inet6Address.startsWith("::") - || inet6Address.endsWith(":") && !inet6Address.endsWith("::")) { - return false; - } - String[] octets = inet6Address.split(":"); - if (containsCompressedZeroes) { - List octetList = new ArrayList(Arrays.asList(octets)); - if (inet6Address.endsWith("::")) { - // String.split() drops ending empty segments - octetList.add(""); - } else if (inet6Address.startsWith("::") && !octetList.isEmpty()) { - octetList.remove(0); - } - octets = octetList.toArray(new String[octetList.size()]); - } - if (octets.length > IPV6_MAX_HEX_GROUPS) { - return false; - } - int validOctets = 0; - int emptyOctets = 0; - for (int index = 0; index < octets.length; index++) { - String octet = octets[index]; - if (octet.length() == 0) { - emptyOctets++; - if (emptyOctets > 1) { - return false; - } - } else { - emptyOctets = 0; - if (octet.contains(".")) { // contains is Java 1.5+ - if (!inet6Address.endsWith(octet)) { - return false; - } - if (index > octets.length - 1 || index > 6) { // CHECKSTYLE IGNORE MagicNumber - // IPV4 occupies last two octets - return false; - } - if (!isValidInet4Address(octet)) { - return false; - } - validOctets += 2; - continue; - } - if (octet.length() > IPV6_MAX_HEX_DIGITS_PER_GROUP) { - return false; - } - int octetInt = 0; - try { - octetInt = Integer.valueOf(octet, BASE_16).intValue(); - } catch (NumberFormatException e) { - return false; - } - if (octetInt < 0 || octetInt > MAX_UNSIGNED_SHORT) { - return false; - } - } - validOctets++; - } - if (validOctets < IPV6_MAX_HEX_GROUPS && !containsCompressedZeroes) { - return false; - } - return true; - } -} diff --git a/api/src/main/java/io/minio/org/apache/commons/validator/routines/RegexValidator.java b/api/src/main/java/io/minio/org/apache/commons/validator/routines/RegexValidator.java deleted file mode 100644 index 31745dae4..000000000 --- a/api/src/main/java/io/minio/org/apache/commons/validator/routines/RegexValidator.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 io.minio.org.apache.commons.validator.routines; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.Serializable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Regular Expression validation (using JDK 1.4+ regex support). - * - *

Construct the validator either for a single regular expression or a set (array) of regular - * expressions. By default validation is case sensitive but constructors are provided to - * allow case in-sensitive validation. For example to create a validator which does case - * in-sensitive validation for a set of regular expressions: - * - *

- * 
- * String[] regexs = new String[] {...};
- * RegexValidator validator = new RegexValidator(regexs, false);
- * 
- * 
- * - *

- * - *

    - *
  • Validate true or false: - *
  • - *
      - *
    • boolean valid = validator.isValid(value); - *
    - *
  • Validate returning an aggregated String of the matched groups: - *
  • - *
      - *
    • String result = validator.validate(value); - *
    - *
  • Validate returning the matched groups: - *
  • - *
      - *
    • String[] result = validator.match(value); - *
    - *
- * - *

Note that patterns are matched against the entire input. - * - *

- * - *

Cached instances pre-compile and re-use {@link Pattern}(s) - which according to the {@link - * Pattern} API are safe to use in a multi-threaded environment. - * - * @version $Revision$ - * @since Validator 1.4 - */ -public class RegexValidator implements Serializable { - - private static final long serialVersionUID = -8832409930574867162L; - - private final Pattern[] patterns; - - /** - * Construct a case sensitive validator for a single regular expression. - * - * @param regex The regular expression this validator will validate against - */ - public RegexValidator(String regex) { - this(regex, true); - } - - /** - * Construct a validator for a single regular expression with the specified case sensitivity. - * - * @param regex The regular expression this validator will validate against - * @param caseSensitive when true matching is case sensitive, otherwise - * matching is case in-sensitive - */ - public RegexValidator(String regex, boolean caseSensitive) { - this(new String[] {regex}, caseSensitive); - } - - /** - * Construct a case sensitive validator that matches any one of the set of regular - * expressions. - * - * @param regexs The set of regular expressions this validator will validate against - */ - public RegexValidator(String[] regexs) { - this(regexs, true); - } - - /** - * Construct a validator that matches any one of the set of regular expressions with the specified - * case sensitivity. - * - * @param regexs The set of regular expressions this validator will validate against - * @param caseSensitive when true matching is case sensitive, otherwise - * matching is case in-sensitive - */ - public RegexValidator(String[] regexs, boolean caseSensitive) { - if (regexs == null || regexs.length == 0) { - throw new IllegalArgumentException("Regular expressions are missing"); - } - patterns = new Pattern[regexs.length]; - int flags = (caseSensitive ? 0 : Pattern.CASE_INSENSITIVE); - for (int i = 0; i < regexs.length; i++) { - if (regexs[i] == null || regexs[i].length() == 0) { - throw new IllegalArgumentException("Regular expression[" + i + "] is missing"); - } - patterns[i] = Pattern.compile(regexs[i], flags); - } - } - - /** - * Validate a value against the set of regular expressions. - * - * @param value The value to validate. - * @return true if the value is valid otherwise false. - */ - public boolean isValid(String value) { - if (value == null) { - return false; - } - for (int i = 0; i < patterns.length; i++) { - if (patterns[i].matcher(value).matches()) { - return true; - } - } - return false; - } - - /** - * Validate a value against the set of regular expressions returning the array of matched groups. - * - * @param value The value to validate. - * @return String array of the groups matched if valid or null if invalid - */ - @SuppressFBWarnings( - value = "PZLA", - justification = "Null is checked, not empty array. API is clear as well.") - public String[] match(String value) { - if (value == null) { - return null; - } - for (int i = 0; i < patterns.length; i++) { - Matcher matcher = patterns[i].matcher(value); - if (matcher.matches()) { - int count = matcher.groupCount(); - String[] groups = new String[count]; - for (int j = 0; j < count; j++) { - groups[j] = matcher.group(j + 1); - } - return groups; - } - } - return null; - } - - /** - * Validate a value against the set of regular expressions returning a String value of the - * aggregated groups. - * - * @param value The value to validate. - * @return Aggregated String value comprised of the groups matched if valid or null - * if invalid - */ - public String validate(String value) { - if (value == null) { - return null; - } - for (int i = 0; i < patterns.length; i++) { - Matcher matcher = patterns[i].matcher(value); - if (matcher.matches()) { - int count = matcher.groupCount(); - if (count == 1) { - return matcher.group(1); - } - StringBuilder buffer = new StringBuilder(); - for (int j = 0; j < count; j++) { - String component = matcher.group(j + 1); - if (component != null) { - buffer.append(component); - } - } - return buffer.toString(); - } - } - return null; - } - - /** - * Provide a String representation of this validator. - * - * @return A String representation of this validator - */ - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(); - buffer.append("RegexValidator{"); - for (int i = 0; i < patterns.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(patterns[i].pattern()); - } - buffer.append("}"); - return buffer.toString(); - } -} diff --git a/api/src/test/java/io/minio/MakeBucketArgsTest.java b/api/src/test/java/io/minio/MakeBucketArgsTest.java index a3cee0322..a47b57994 100644 --- a/api/src/test/java/io/minio/MakeBucketArgsTest.java +++ b/api/src/test/java/io/minio/MakeBucketArgsTest.java @@ -21,25 +21,25 @@ import org.junit.Test; public class MakeBucketArgsTest { - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBuild() { MakeBucketArgs.builder().build(); Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBucketBuild1() { MakeBucketArgs.builder().objectLock(false).build(); Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBucketBuild2() { MakeBucketArgs.builder().bucket(null).build(); Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBucketBuild3() { MakeBucketArgs.builder().bucket("mybucket").bucket(null).build(); Assert.fail("exception should be thrown"); diff --git a/api/src/test/java/io/minio/MinioClientTest.java b/api/src/test/java/io/minio/MinioClientTest.java index bc97d607b..edb18fb3a 100644 --- a/api/src/test/java/io/minio/MinioClientTest.java +++ b/api/src/test/java/io/minio/MinioClientTest.java @@ -19,8 +19,6 @@ import io.minio.errors.InvalidResponseException; import io.minio.errors.MinioException; -import io.minio.http.Method; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -38,7 +36,7 @@ public class MinioClientTest { private static final String CONTENT_TYPE = "Content-Type"; private static final String CONTENT_LENGTH = "Content-Length"; - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEndpoint1() throws MinioException { MinioClient.builder().endpoint((String) null).build(); Assert.fail("exception should be thrown"); @@ -103,7 +101,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -118,7 +116,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -129,7 +127,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -144,7 +142,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -156,7 +154,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -169,7 +167,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -185,7 +183,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -197,7 +195,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -213,7 +211,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -226,7 +224,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -243,7 +241,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -258,7 +256,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -273,7 +271,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -289,7 +287,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -306,7 +304,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -322,7 +320,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -338,7 +336,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -355,7 +353,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -382,7 +380,7 @@ public void testCustomHttpClientClose() throws Exception { Assert.assertTrue(httpClient.dispatcher().executorService().isShutdown()); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testBucketName1() throws NoSuchAlgorithmException, IOException, InvalidKeyException, MinioException { StatObjectArgs.builder().bucket(null); @@ -432,7 +430,7 @@ public void testBucketName7() Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testObjectName1() throws NoSuchAlgorithmException, IOException, InvalidKeyException, MinioException { StatObjectArgs.builder().object(null); @@ -470,7 +468,7 @@ public void testReadSse1() StatObjectArgs.builder() .bucket("mybucket") .object("myobject") - .ssec(new ServerSideEncryptionCustomerKey(keyGen.generateKey())) + .ssec(new ServerSideEncryption.CustomerKey(keyGen.generateKey())) .build()); Assert.fail("exception should be thrown"); } @@ -482,9 +480,11 @@ public void testWriteSse1() KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); client.putObject( - PutObjectArgs.builder().bucket("mybucket").object("myobject").stream( - new ByteArrayInputStream(new byte[] {}), 0, -1) - .sse(new ServerSideEncryptionCustomerKey(keyGen.generateKey())) + PutObjectArgs.builder() + .bucket("mybucket") + .object("myobject") + .data(new byte[0], 0) + .sse(new ServerSideEncryption.CustomerKey(keyGen.generateKey())) .build()); Assert.fail("exception should be thrown"); } @@ -496,9 +496,11 @@ public void testWriteSse2() Map myContext = new HashMap<>(); myContext.put("key1", "value1"); client.putObject( - PutObjectArgs.builder().bucket("mybucket").object("myobject").stream( - new ByteArrayInputStream(new byte[] {}), 0, -1) - .sse(new ServerSideEncryptionKms("keyId", myContext)) + PutObjectArgs.builder() + .bucket("mybucket") + .object("myobject") + .data(new byte[0], 0) + .sse(new ServerSideEncryption.KMS("keyId", myContext)) .build()); Assert.fail("exception should be thrown"); } diff --git a/api/src/test/java/io/minio/StatObjectArgsTest.java b/api/src/test/java/io/minio/StatObjectArgsTest.java index e40c419d7..74740981f 100644 --- a/api/src/test/java/io/minio/StatObjectArgsTest.java +++ b/api/src/test/java/io/minio/StatObjectArgsTest.java @@ -17,6 +17,7 @@ package io.minio; +import io.minio.errors.MinioException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.KeyGenerator; @@ -24,25 +25,25 @@ import org.junit.Test; public class StatObjectArgsTest { - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBuild() { StatObjectArgs.builder().build(); Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBucketBuild1() { StatObjectArgs.builder().object("myobject").build(); Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBucketBuild2() { StatObjectArgs.builder().object("myobject").bucket(null).build(); Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyBucketBuild3() { StatObjectArgs.builder().bucket("mybucket").bucket(null).build(); Assert.fail("exception should be thrown"); @@ -54,7 +55,7 @@ public void testEmptyRegionBuild() { Assert.fail("exception should be thrown"); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testEmptyObjectBuild1() { StatObjectArgs.builder().object(null).build(); Assert.fail("exception should be thrown"); @@ -67,11 +68,11 @@ public void testEmptyObjectBuild2() { } @Test - public void testBuild() throws NoSuchAlgorithmException, InvalidKeyException { + public void testBuild() throws InvalidKeyException, MinioException, NoSuchAlgorithmException { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); StatObjectArgs args = StatObjectArgs.builder() .bucket("mybucket") diff --git a/build.gradle b/build.gradle index 4e9cce5c0..461c55eec 100644 --- a/build.gradle +++ b/build.gradle @@ -15,13 +15,13 @@ */ /********************************/ -/* gradleVersion = '8.12.1' */ +/* gradleVersion = '8.14.3' */ /********************************/ plugins { id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'com.github.spotbugs' version '6.1.3' - id 'org.jreleaser' version '1.17.0' + id 'com.github.spotbugs' version '6.1.13' + id 'org.jreleaser' version '1.19.0' id 'com.diffplug.spotless' version '6.13.0' } @@ -29,7 +29,7 @@ plugins { allprojects { group = 'io.minio' - version = '8.6.0' + version = '9.0.0' if (!project.hasProperty('release')) { version += '-DEV' } @@ -47,18 +47,18 @@ subprojects { dependencies { api 'com.carrotsearch.thirdparty:simple-xml-safe:2.7.1' - api 'com.google.guava:guava:33.4.0-jre' - api 'com.squareup.okhttp3:okhttp:4.12.0' - api 'com.fasterxml.jackson.core:jackson-annotations:2.18.2' - api 'com.fasterxml.jackson.core:jackson-core:2.18.2' - api 'com.fasterxml.jackson.core:jackson-databind:2.18.2' - api 'org.bouncycastle:bcprov-jdk18on:1.80' + api 'com.google.guava:guava:33.4.8-jre' + api 'com.squareup.okhttp3:okhttp:5.1.0' + api 'com.fasterxml.jackson.core:jackson-annotations:2.19.1' + api 'com.fasterxml.jackson.core:jackson-core:2.19.1' + api 'com.fasterxml.jackson.core:jackson-databind:2.19.1' + api 'org.bouncycastle:bcprov-jdk18on:1.81' api 'org.apache.commons:commons-compress:1.27.1' api 'commons-codec:commons-codec:1.18.0' api 'org.xerial.snappy:snappy-java:1.1.10.7' compileOnly 'com.github.spotbugs:spotbugs-annotations:4.8.6' - testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0' + testImplementation 'com.squareup.okhttp3:mockwebserver:5.1.0' testImplementation 'junit:junit:4.13.2' } @@ -248,7 +248,7 @@ project(':adminapi') { dependencies { api project(':api') - api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.19.1' testImplementation project(':api') } diff --git a/docs/API.md b/docs/API.md index 334d3c385..ee72ac8f1 100644 --- a/docs/API.md +++ b/docs/API.md @@ -196,7 +196,7 @@ MinioClient s3Client = MinioClient s3Client = MinioClient.builder() .endpoint("s3.amazonaws.com", 443, true) - .credentials("YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"). + .credentials("YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY") .region("eu-west-2") .build(); @@ -1257,9 +1257,10 @@ Enables legal hold on an object. __Parameters__ -| Parameter | Type | Description | -|:---------------|:------------------------------|:-------------| -| ``args`` | _[EnableObjectLegalHoldArgs]_ | Argumments. | +| Parameter | Type | Description | +|:----------|:------------------------------|:------------| +| ``args`` | _[EnableObjectLegalHoldArgs]_ | Arguments. | + __Example__ ```java @@ -1376,9 +1377,9 @@ __Parameters__ | ``args`` | _[GetObjectAttributesArgs]_ | Arguments. | -| Returns | -|:-------------------------------------------| -| _[GetObjectAttributesResponse]_ - Respone. | +| Returns | +|:--------------------------------------------| +| _[GetObjectAttributesResponse]_ - Response. | __Example__ ```java @@ -1988,7 +1989,7 @@ minioClient.setObjectTags( ### statObject(StatObjectArgs args) -`public ObjectStat statObject(StatObjectArgs args)` _[[Javadoc]](http://minio.github.io/minio-java/io/minio/MinioClient.html#statObject-io.minio.StatObjectArgs-)_ +`public StatObjectResponse statObject(StatObjectArgs args)` _[[Javadoc]](http://minio.github.io/minio-java/io/minio/MinioClient.html#statObject-io.minio.StatObjectArgs-)_ Gets object information and metadata of an object. @@ -1997,19 +1998,19 @@ __Parameters__ |:----------|:-------------------|:------------| | ``args`` | _[StatObjectArgs]_ | Arguments. | -| Returns | -|:------------------------------------------------------------| -| _[ObjectStat]_ - Populated object information and metadata. | +| Returns | +|:--------------------------------------------------------------------| +| _[StatObjectResponse]_ - Populated object information and metadata. | __Example__ ```java // Get information of an object. -ObjectStat objectStat = +StatObjectResponse response = minioClient.statObject( StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); // Get information of SSE-C encrypted object. -ObjectStat objectStat = +StatObjectResponse response = minioClient.statObject( StatObjectArgs.builder() .bucket("my-bucketname") @@ -2018,7 +2019,7 @@ ObjectStat objectStat = .build()); // Get information of a versioned object. -ObjectStat objectStat = +StatObjectResponse response = minioClient.statObject( StatObjectArgs.builder() .bucket("my-bucketname") @@ -2027,7 +2028,7 @@ ObjectStat objectStat = .build()); // Get information of a SSE-C encrypted versioned object. -ObjectStat objectStat = +StatObjectResponse response = minioClient.statObject( StatObjectArgs.builder() .bucket("my-bucketname") @@ -2070,7 +2071,7 @@ ObjectStat objectStat = [InputSerialization]: http://minio.github.io/minio-java/io/minio/messages/InputSerialization.html [OutputSerialization]: http://minio.github.io/minio-java/io/minio/messages/OutputSerialization.html [Retention]: http://minio.github.io/minio-java/io/minio/messages/Retention.html -[ObjectStat]: http://minio.github.io/minio-java/io/minio/ObjectStat.html +[StatObjectResponse]: http://minio.github.io/minio-java/io/minio/StatObjectResponse.html [DeleteError]: http://minio.github.io/minio-java/io/minio/messages/DeleteError.html [SelectResponseStream]: http://minio.github.io/minio-java/io/minio/SelectResponseStream.html [MakeBucketArgs]: http://minio.github.io/minio-java/io/minio/MakeBucketArgs.html diff --git a/docs/zh_CN/API.md b/docs/zh_CN/API.md deleted file mode 100644 index 5cbaa6f14..000000000 --- a/docs/zh_CN/API.md +++ /dev/null @@ -1,1446 +0,0 @@ -# Java Client API参考文档 [![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io) - -## 初始化Minio Client object。 - -## MinIO - -```java -MinioClient minioClient = new MinioClient("https://play.min.io", "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); -``` - -## AWS S3 - - -```java -MinioClient s3Client = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); -``` - -| 存储桶操作 | 文件对象操作 | Presigned操作 | 存储桶策略 -|:--- |:--- |:--- |:--- | -| [`makeBucket`](#makeBucket) |[`getObject`](#getObject) |[`presignedGetObject`](#presignedGetObject) | [`getBucketPolicy`](#getBucketPolicy) | -| [`listBuckets`](#listBuckets) | [`putObject`](#putObject) | [`presignedPutObject`](#presignedPutObject) | [`setBucketPolicy`](#setBucketPolicy) | -| [`bucketExists`](#bucketExists) | [`copyObject`](#copyObject) | [`presignedPostPolicy`](#presignedPostPolicy) | | -| [`removeBucket`](#removeBucket) | [`statObject`](#statObject) | | | -| [`listObjects`](#listObjects) | [`removeObject`](#removeObject) | | | -| [`listIncompleteUploads`](#listIncompleteUploads) | [`removeIncompleteUpload`](#removeIncompleteUpload) | | | - - -## 1. 构造函数 - - - -| | -|---| -|`public MinioClient(String endpoint) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的endpoint以及匿名方式创建一个Minio client对象。| -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.lang.String-) | - - -| | -|---| -|`public MinioClient(URL url) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的url以及匿名方式创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.net.URL-) | - - -| | -|---| -| `public MinioClient(com.squareup.okhttp.HttpUrl url) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -|使用给定的HttpUrl以及匿名方式创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-com.squareup.okhttp.HttpUrl-) | - -| | -|---| -| `public MinioClient(String endpoint, String accessKey, String secretKey) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的endpoint、access key和secret key创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.lang.String-java.lang.String-java.lang.String-)| - -| | -|---| -| `public MinioClient(String endpoint, int port, String accessKey, String secretKey) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的endpoint、port、access key和secret key创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.lang.String-int-java.lang.String-java.lang.String-) | - - -| | -|---| -| `public MinioClient(String endpoint, String accessKey, String secretKey, boolean secure) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的endpoint、access key、secret key和一个secure选项(是否使用https)创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.lang.String-java.lang.String-java.lang.String-boolean-) | - - -| | -|---| -| `public MinioClient(String endpoint, int port, String accessKey, String secretKey, boolean secure) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的endpoint、port、access key、secret key和一个secure选项(是否使用https)创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.lang.String-int-java.lang.String-java.lang.String-boolean-) | - -| | -|---| -| `public MinioClient(com.squareup.okhttp.HttpUrl url, String accessKey, String secretKey) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的HttpUrl对象、access key、secret key创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-com.squareup.okhttp.HttpUrl-java.lang.String-java.lang.String-) | - - -| | -|---| -| `public MinioClient(URL url, String accessKey, String secretKey) throws NullPointerException, InvalidEndpointException, InvalidPortException` | -| 使用给定的URL对象、access key、secret key创建一个Minio client对象。 | -| [查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#MinioClient-java.net.URL-java.lang.String-java.lang.String-) | - - -__参数__ - -| 参数 | 类型 | 描述 | -|---|---|---| -| `endpoint` | _string_ | endPoint是一个URL,域名,IPv4或者IPv6地址。以下是合法的endpoints: | -| | |https://s3.amazonaws.com | -| | |https://play.min.io | -| | |localhost | -| | |play.min.io| -| `port` | _int_ | TCP/IP端口号。可选,默认值是,如果是http,则默认80端口,如果是https,则默认是443端口。| -| `accessKey` | _string_ |accessKey类似于用户ID,用于唯一标识你的账户。 | -|`secretKey` | _string_ | secretKey是你账户的密码。| -|`secure` | _boolean_ |如果是true,则用的是https而不是http,默认值是true。 | -|`url` | _URL_ |Endpoint URL对象。| -|`url` | _HttpURL_ |Endpoint HttpUrl对象。 | - - -__示例__ - - -### MinIO - - -```java -// 1. public MinioClient(String endpoint) -MinioClient minioClient = new MinioClient("https://play.min.io"); - -// 2. public MinioClient(URL url) -MinioClient minioClient = new MinioClient(new URL("https://play.min.io")); - -// 3. public MinioClient(com.squareup.okhttp.HttpUrl url) - MinioClient minioClient = new MinioClient(new HttpUrl.parse("https://play.min.io")); - -// 4. public MinioClient(String endpoint, String accessKey, String secretKey) -MinioClient minioClient = new MinioClient("https://play.min.io", "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - -// 5. public MinioClient(String endpoint, int port, String accessKey, String secretKey) -MinioClient minioClient = new MinioClient("https://play.min.io", 9000, "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - -// 6. public MinioClient(String endpoint, String accessKey, String secretKey, boolean insecure) -MinioClient minioClient = new MinioClient("https://play.min.io", "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", true); - -// 7. public MinioClient(String endpoint, int port, String accessKey, String secretKey, boolean insecure) -MinioClient minioClient = new MinioClient("https://play.min.io", 9000, "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", true); - -// 8. public MinioClient(com.squareup.okhttp.HttpUrl url, String accessKey, String secretKey) - MinioClient minioClient = new MinioClient(new URL("https://play.min.io"), "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - -// 9. public MinioClient(URL url, String accessKey, String secretKey) -MinioClient minioClient = new MinioClient(HttpUrl.parse("https://play.min.io"), "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); -``` - - -### AWS S3 - - -```java -// 1. public MinioClient(String endpoint) -MinioClient s3Client = new MinioClient("https://s3.amazonaws.com"); - -// 2. public MinioClient(URL url) -MinioClient minioClient = new MinioClient(new URL("https://s3.amazonaws.com")); - -// 3. public MinioClient(com.squareup.okhttp.HttpUrl url) - MinioClient s3Client = new MinioClient(new HttpUrl.parse("https://s3.amazonaws.com")); - -// 4. public MinioClient(String endpoint, String accessKey, String secretKey) -MinioClient s3Client = new MinioClient("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); - -// 5. public MinioClient(String endpoint, int port, String accessKey, String secretKey) -MinioClient s3Client = new MinioClient("s3.amazonaws.com", 80, "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); - -// 6. public MinioClient(String endpoint, String accessKey, String secretKey, boolean insecure) -MinioClient s3Client = new MinioClient("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", false); - -// 7. public MinioClient(String endpoint, int port, String accessKey, String secretKey, boolean insecure) -MinioClient s3Client = new MinioClient("s3.amazonaws.com", 80, "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY",false); - -// 8. public MinioClient(com.squareup.okhttp.HttpUrl url, String accessKey, String secretKey) - MinioClient s3Client = new MinioClient(new URL("s3.amazonaws.com"), "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); - -// 9. public MinioClient(URL url, String accessKey, String secretKey) -MinioClient s3Client = new MinioClient(HttpUrl.parse("s3.amazonaws.com"), "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); -``` - -## 2. 存储桶操作 - - -### makeBucket(String bucketName) -`public void makeBucket(String bucketName)` - -创建一个新的存储桶 - -[查看Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#makeBucket-java.lang.String-) - -__参数__ - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ |存储桶名称 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``None`` | 异常列表: | -| | ``InvalidBucketNameException`` : 非法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常 | -| | ``ErrorResponseException`` : 执行失败 | -| | ``InternalException`` : 内部异常 | - - -__示例__ - - -```java -try { - // 如存储桶不存在,创建之。 - boolean found = minioClient.bucketExists("mybucket"); - if (found) { - System.out.println("mybucket already exists"); - } else { - // 创建名为'my-bucketname'的存储桶。 - minioClient.makeBucket("mybucket"); - System.out.println("mybucket is created successfully"); - } -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### listBuckets() - -`public List listBuckets()` - -列出所有存储桶。 - -[查看Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#listBuckets--) - -|返回值类型 | 异常 | -|:--- |:--- | -| ``List Bucket`` : List of bucket type. | 异常列表: | -| | ``NoResponseException`` : 服务端无响应 | -| | ``IOException`` : 连接异常 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常 | -| | ``ErrorResponseException`` :执行失败异溃| -| | ``InternalException`` : 内部错误| - - -__示例__ - - -```java -try { - // 列出所有存储桶 - List bucketList = minioClient.listBuckets(); - for (Bucket bucket : bucketList) { - System.out.println(bucket.creationDate() + ", " + bucket.name()); - } -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### bucketExists(String bucketName) - -`public boolean bucketExists(String bucketName)` - -检查存储桶是否存在。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#bucketExists-java.lang.String-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称 | - - -| 返回值值类型 | 异常 | -|:--- |:--- | -| ``boolean``: true if the bucket exists | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - - -__示例__ - - -```java -try { - // 检查'my-bucketname'是否存在。 - boolean found = minioClient.bucketExists("mybucket"); - if (found) { - System.out.println("mybucket exists"); - } else { - System.out.println("mybucket does not exist"); - } -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - - -### removeBucket(String bucketName) - -`public void removeBucket(String bucketName)` - -删除一个存储桶。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#removeBucket-java.lang.String-) - -注意: - removeBucket不会删除存储桶里的对象,你需要通过removeObject API来删除它们。 - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - -__示例__ - - -```java -try { - // 删除之前先检查`my-bucket`是否存在。 - boolean found = minioClient.bucketExists("mybucket"); - if (found) { - // 删除`my-bucketname`存储桶,注意,只有存储桶为空时才能删除成功。 - minioClient.removeBucket("mybucket"); - System.out.println("mybucket is removed successfully"); - } else { - System.out.println("mybucket does not exist"); - } -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### listObjects(String bucketName, String prefix, boolean recursive, boolean useVersion1) - -`public Iterable> listObjects(String bucketName, String prefix, boolean recursive, boolean useVersion1)` - -列出某个存储桶中的所有对象。 - -[查看Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#listObjects-java.lang.String-java.lang.String-boolean-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``prefix`` | _String_ | 对象名称的前缀 | -| ``recursive`` | _boolean_ | 是否递归查找,如果是false,就模拟文件夹结构查找。 | -| ``useVersion1`` | _boolean_ | 如果是true, 使用版本1 REST API | - - -|返回值类型 | 异常 | -|:--- |:--- | -| ``Iterable>``:an iterator of Result Items. | _None_ | - - -__示例__ - - -```java -try { - // 检查'mybucket'是否存在。 - boolean found = minioClient.bucketExists("mybucket"); - if (found) { - // 列出'my-bucketname'里的对象 - Iterable> myObjects = minioClient.listObjects("mybucket"); - for (Result result : myObjects) { - Item item = result.get(); - System.out.println(item.lastModified() + ", " + item.size() + ", " + item.objectName()); - } - } else { - System.out.println("mybucket does not exist"); - } -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - - -### listIncompleteUploads(String bucketName, String prefix, boolean recursive) - -`public Iterable> listIncompleteUploads(String bucketName, String prefix, boolean recursive)` - -列出存储桶中被部分上传的对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#listIncompleteUploads-java.lang.String-java.lang.String-boolean-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``prefix`` | _String_ | 对象名称的前缀,列出有该前缀的对象 | -| ``recursive`` | _boolean_ | 是否递归查找,如果是false,就模拟文件夹结构查找。 | - - -|返回值类型 | 异常 | -|:--- |:--- | -| ``Iterable>``: an iterator of Upload. | _None_ | - - -__示例__ - - -```java -try { - // 检查'mybucket'是否存在。 - boolean found = minioClient.bucketExists("mybucket"); - if (found) { - // 列出'mybucket'中所有未完成的multipart上传的的对象。 - Iterable> myObjects = minioClient.listIncompleteUploads("mybucket"); - for (Result result : myObjects) { - Upload upload = result.get(); - System.out.println(upload.uploadId() + ", " + upload.objectName()); - } - } else { - System.out.println("mybucket does not exist"); - } -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### getBucketPolicy(String bucketName, String objectPrefix) -`public PolicyType getBucketPolicy(String bucketName, String objectPrefix)` - -获得指定对象前缀的存储桶策略。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#getBucketPolicy-java.lang.String-java.lang.String-) - -__参数__ - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectPrefix`` | _String_ | 策略适用的对象的前缀 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``PolicyType``: The current bucket policy type for a given bucket and objectPrefix. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | -| | ``InvalidBucketNameException `` : 不合法的存储桶名称。 | -| | ``InvalidObjectPrefixException`` : 不合法的对象前缀 | -| | ``NoSuchAlgorithmException`` : 找不到相应的签名算法。 | -| | ``InsufficientDataException`` : 在读到相应length之前就得到一个EOFException。 | - - -__示例__ - - -```java -try { - System.out.println("Current policy: " + minioClient.getBucketPolicy("myBucket", "downloads")); -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### setBucketPolicy(String bucketName, String objectPrefix, PolicyType policy) -`public void setBucketPolicy(String bucketName, String objectPrefix, PolicyType policy)` - -给一个存储桶+对象前缀设置策略。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#setBucketPolicy-java.lang.String-java.lang.String-io.minio.BucketPolicy-) - -__参数__ - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectPrefix`` | _String_ | 对象前缀。 | -| ``policy`` | _PolicyType_ | 要赋予的策略,可选值有[PolicyType.NONE, PolicyType.READ_ONLY, PolicyType.READ_WRITE, PolicyType.WRITE_ONLY]. | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | -| | ``InvalidBucketNameException `` : 不合法的存储桶名称。 | -| | ``InvalidObjectPrefixException`` : 不合法的对象前缀 | -| | ``NoSuchAlgorithmException`` : 找不到相应的签名算法。 | -| | ``InsufficientDataException`` : 在读到相应length之前就得到一个EOFException。 | - - - -__示例__ - - -```java -try { - minioClient.setBucketPolicy("myBucket", "uploads", PolicyType.READ_ONLY); -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - -## 3. Object operations - - -### getObject(String bucketName, String objectName) - -`public InputStream getObject(String bucketName, String objectName, long offset)` - -以流的形式下载一个对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#getObject-java.lang.String-java.lang.String-long-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``InputStream``: InputStream containing the object data. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - -__示例__ - - -```java -try { - // 调用statObject()来判断对象是否存在。 - // 如果不存在, statObject()抛出异常, - // 否则则代表对象存在。 - minioClient.statObject("mybucket", "myobject"); - - // 获取"myobject"的输入流。 - InputStream stream = minioClient.getObject("mybucket", "myobject"); - - // 读取输入流直到EOF并打印到控制台。 - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead)); - } - - // 关闭流,此处为示例,流关闭最好放在finally块。 - stream.close(); -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### getObject(String bucketName, String objectName, long offset, Long length) - -`public InputStream getObject(String bucketName, String objectName, long offset, Long length)` - -下载对象指定区域的字节数组做为流。(断点下载) - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#getObject-java.lang.String-java.lang.String-long-java.lang.Long-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``offset`` | _Long_ | ``offset`` 是起始字节的位置 | -| ``length`` | _Long_ | ``length``是要读取的长度 (可选,如果无值则代表读到文件结尾)。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``InputStream`` : InputStream containing the object's data. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - -__示例__ - - -```java -try { - - // 调用statObject()来判断对象是否存在。 - // 如果不存在, statObject()抛出异常, - // 否则则代表对象存在。 - minioClient.statObject("mybucket", "myobject"); - - // 获取指定offset和length的"myobject"的输入流。 - InputStream stream = minioClient.getObject("mybucket", "myobject", 1024L, 4096L); - - // 读取输入流直到EOF并打印到控制台。 - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead)); - } - - // 关闭流。 - stream.close(); -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### getObject(String bucketName, String objectName, String fileName) - -`public void getObject(String bucketName, String objectName, String fileName)` - -下载并将文件保存到本地。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#getObject-java.lang.String-java.lang.String-java.lang.String-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``fileName`` | _String_ | File name. | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - -__示例__ - -```java -try { - // 调用statObject()来判断对象是否存在。 - // 如果不存在, statObject()抛出异常, - // 否则则代表对象存在。 - minioClient.statObject("mybucket", "myobject"); - - // 获取myobject的流并保存到photo.jpg文件中。 - minioClient.getObject("mybucket", "myobject", "photo.jpg"); - -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### getObject(String bucketName, String objectName, SecretKey key) - -`public CipherInputStream getObject(String bucketName, String objectName, SecretKey key)` - -在给定的存储桶中获取整个加密对象的数据作为InputStream,然后用传入的master key解密和加密对象关联的content key。然后创建一个含有InputStream和Cipher的CipherInputStream。这个Cipher被初始为用于使用content key进行解密,所以CipherInputStream会在返回数据前,尝试读取数据并进行解密。所以read()方法返回的是处理过的原始对象数据。 - -CipherInputStream必须用完关闭,否则连接不会被释放。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#getObject-java.lang.String-java.lang.String-javax.crypto.SecretKey-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``key`` | _SecretKey_ | [SecretKey](https://docs.oracle.com/javase/7/docs/api/javax/crypto/SecretKey.html)类型的数据。| - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | -| | ``InvalidEncryptionMetadataException`` : 加密秘钥错误。 | -| | ``BadPaddingException`` : 错误的padding | -| | ``IllegalBlockSizeException`` : 不正确的block size | -| | ``NoSuchPaddingException`` : 错误的pading类型 | -| | ``InvalidAlgorithmParameterException`` : 该算法不存在 | - -__示例__ - -```java -try { - // 调用statObject()来判断对象是否存在。 - // 如果不存在, statObject()抛出异常, - // 否则则代表对象存在。 - minioClient.statObject("mybucket", "myobject"); - - //生成256位AES key。 - KeyGenerator symKeyGenerator = KeyGenerator.getInstance("AES"); - symKeyGenerator.init(256); - SecretKey symKey = symKeyGenerator.generateKey(); - - // 获取对象数据并保存到photo.jpg - InputStream stream = minioClient.getObject("testbucket", "my-objectname", symKey); - - // 读流到EOF,并输出到控制台。 - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); - } - - // 关闭流。 - stream.close(); - -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### getObject(String bucketName, String objectName, KeyPair key) - -`public InputStream getObject(String bucketName, String objectName, KeyPair key)` - -在给定的存储桶中获取整个加密对象的数据作为InputStream,然后用传入的master keyPair解密和加密对象关联的content key。然后创建一个含有InputStream和Cipher的CipherInputStream。这个Cipher被初始为用于使用content key进行解密,所以CipherInputStream会在返回数据前,尝试读取数据并进行解密。所以read()方法返回的是处理过的原始对象数据。 - -CipherInputStream必须用完关闭,否则连接不会被释放。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#getObject-java.lang.String-java.lang.String-java.security.KeyPair-) - -__参数__ - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``key`` | _KeyPair_ | RSA [KeyPair](https://docs.oracle.com/javase/7/docs/api/java/security/KeyPair.html)类型的对象。 | - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | -| | ``InvalidEncryptionMetadataException`` : 加密秘钥错误。 | -| | ``BadPaddingException`` : 错误的padding | -| | ``IllegalBlockSizeException`` : 不正确的block size | -| | ``NoSuchPaddingException`` : 错误的pading类型 | -| | ``InvalidAlgorithmParameterException`` : 该算法不存在 | - -__示例__ - -```java -try { - // 调用statObject()来判断对象是否存在。 - // 如果不存在, statObject()抛出异常, - // 否则则代表对象存在。 - minioClient.statObject("mybucket", "myobject"); - - KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA"); - keyGenerator.initialize(1024, new SecureRandom()); - KeyPair keypair = keyGenerator.generateKeyPair(); - - // 获取对象数据并保存到photo.jpg - InputStream stream = minioClient.getObject("testbucket", "my-objectname", keypair); - - // 读流到EOF,并输出到控制台。 - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); - } - - // 关闭流。 - stream.close(); - -} catch (MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### putObject(String bucketName, String objectName, InputStream stream, long size, String contentType) - -`public void putObject(String bucketName, String objectName, InputStream stream, long size, String contentType)` - -通过InputStream上传对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#putObject-java.lang.String-java.lang.String-java.io.InputStream-long-java.lang.String-) - - -__参数__ - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``stream`` | _InputStream_ | 要上传的流。 | -| ``size`` | _long_ | 要上传的`stream`的size | -| ``contentType`` | _String_ | Content type。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - -__示例__ - - -单个对象的最大大小限制在5TB。putObject在对象大于5MiB时,自动使用multiple parts方式上传。这样,当上传失败时,客户端只需要上传未成功的部分即可(类似断点上传)。上传的对象使用MD5SUM签名进行完整性验证。 - -```java -try { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append("Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append("Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append("Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append("The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append("How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append("Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append("A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("- --\n"); - } - ByteArrayInputStream bais = new - ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - // 创建对象 - minioClient.putObject("mybucket", "myobject", bais, bais.available(), "application/octet-stream"); - bais.close(); - System.out.println("myobject is uploaded successfully"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### putObject(String bucketName, String objectName, String fileName) - -`public void putObject(String bucketName, String objectName, String fileName)` - -通过文件上传到对象中。 -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#putObject-java.lang.String-java.lang.String-java.lang.String-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``fileName`` | _String_ | File name. | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - -__示例__ - - -```java -try { - minioClient.putObject("mybucket", "island.jpg", "/mnt/photos/island.jpg") - System.out.println("island.jpg is uploaded successfully"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - -### putObject(String bucketName, String objectName, InputStream stream, long size, String contentType, SecretKey key) - -`public void putObject(String bucketName, String objectName, InputStream stream, long size, String contentType, - SecretKey key)` - -拿到流的数据,使用随机生成的content key进行加密,并上传到指定存储桶中。同时将加密后的content key和iv做为加密对象有header也上传到存储桶中。content key使用传入到该方法的master key进行加密。 - -如果对象大于5MB,客户端会自动进行multi part上传。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#putObject-java.lang.String-java.lang.String-java.io.InputStream-long-java.lang.String-javax.crypto.SecretKey-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``stream`` | _InputStream_ | 要上传的流。 | -| ``size`` | _long_ | 要上传的流的大小。| -| ``contentType`` | _String_ | Content type。| -| ``key`` | _SecretKey_ | 用AES初使化的对象[SecretKey](https://docs.oracle.com/javase/7/docs/api/javax/crypto/SecretKey.html)。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | -| | ``InvalidAlgorithmParameterException`` : 错误的加密算法。 | -| | ``BadPaddingException`` : 不正确的padding. | -| | ``IllegalBlockSizeException`` : 不正确的block。 | -| | ``NoSuchPaddingException`` : 错误的padding类型。 | - -__示例__ - -对象使用随机生成的key进行加密,然后这个用于加密数据的key又被由仅被client知道的master key(封装在encryptionMaterials对象里)进行加密。这个被加密后的key和IV做为对象的header和加密后的对象一起被上传到存储服务上。 - -```java -try { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append("Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append("Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append("Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append("The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append("How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append("Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append("A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("- --\n"); - } - ByteArrayInputStream bais = new - ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - //生成256位AES key. - KeyGenerator symKeyGenerator = KeyGenerator.getInstance("AES"); - symKeyGenerator.init(256); - SecretKey symKey = symKeyGenerator.generateKey(); - - // 创建一个对象 - minioClient.putObject("mybucket", "myobject", bais, bais.available(), "application/octet-stream", symKey); - bais.close(); - System.out.println("myobject is uploaded successfully"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### putObject(String bucketName, String objectName, InputStream stream, long size, String contentType, KeyPair key) - -`public void putObject(String bucketName, String objectName, InputStream stream, long size, String contentType, - KeyPair key)` - - -拿到流的数据,使用随机生成的content key进行加密,并上传到指定存储桶中。同时将加密后的content key和iv做为加密对象有header也上传到存储桶中。content key使用传入到该方法的master key进行加密。 - -如果对象大于5MB,客户端会自动进行multi part上传。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#putObject-java.lang.String-java.lang.String-java.io.InputStream-long-java.lang.String-java.security.KeyPair-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``stream`` | _InputStream_ | 要上传的流。 | -| ``size`` | _long_ | 要上传的流的大小。 | -| ``contentType`` | _String_ | Content type。 | -| ``key`` | _KeyPair_ | 一个RSA [KeyPair](https://docs.oracle.com/javase/7/docs/api/java/security/KeyPair.html)的对象。 | - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | -| | ``InvalidAlgorithmParameterException`` : 错误的加密算法。 | -| | ``BadPaddingException`` : 不正确的padding。 | -| | ``IllegalBlockSizeException`` : 不正确的block。 | -| | ``NoSuchPaddingException`` : 错误的pading类型。 | - -__示例__ - -对象使用随机生成的key进行加密,然后这个用于加密数据的key又被由仅被client知道的master key(封装在encryptionMaterials对象里)进行加密。这个被加密后的key和IV做为对象的header和加密后的对象一起被上传到存储服务上。 - -```java -try { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append("Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append("Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append("Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append("The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append("How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append("Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append("A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("- --\n"); - } - ByteArrayInputStream bais = new - ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA"); - keyGenerator.initialize(1024, new SecureRandom()); - KeyPair keypair = keyGenerator.generateKeyPair(); - - // Create an object - minioClient.putObject("mybucket", "myobject", bais, bais.available(), "application/octet-stream", keypair); - bais.close(); - System.out.println("myobject is uploaded successfully"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### statObject(String bucketName, String objectName) - -*`public ObjectStat statObject(String bucketName, String objectName)`* - -获取对象的元数据。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#statObject-java.lang.String-java.lang.String-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``ObjectStat``: Populated object meta data. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - -__示例__ - - -```java -try { - // 获得对象的元数据。 - ObjectStat objectStat = minioClient.statObject("mybucket", "myobject"); - System.out.println(objectStat); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### copyObject(String bucketName, String objectName, String destBucketName, String destObjectName, CopyConditions cpConds, Map metadata) - -*`public void copyObject(String bucketName, String objectName, String destBucketName, String destObjectName, CopyConditions cpConds, Map metadata)`* - -从objectName指定的对象中将数据拷贝到destObjectName指定的对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#copyObject-java.lang.String-java.lang.String-java.lang.String-java.lang.String-io.minio.CopyConditions-) - -__参数__ - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 源存储桶名称。 | -| ``objectName`` | _String_ | 源存储桶中的源对象名称。 | -| ``destBucketName`` | _String_ | 目标存储桶名称。 | -| ``destObjectName`` | _String_ | 要创建的目标对象名称,如果为空,默认为源对象名称。| -| ``copyConditions`` | _CopyConditions_ | 拷贝操作的一些条件Map。| -| ``metadata`` | _Map_ | 给目标对象的元数据Map。| - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - -__示例__ - -本API执行了一个服务端的拷贝操作。 - -```java -try { - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setMatchETagNone("TestETag"); - - minioClient.copyObject("mybucket", "island.jpg", "mydestbucket", "processed.png", copyConditions); - System.out.println("island.jpg is uploaded successfully"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### removeObject(String bucketName, String objectName) - -`public void removeObject(String bucketName, String objectName)` - -删除一个对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#removeObject-java.lang.String-java.lang.String-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - - -__示例__ - - -```java -try { - // 从mybucket中删除myobject。 - minioClient.removeObject("mybucket", "myobject"); - System.out.println("successfully removed mybucket/myobject"); -} catch (MinioException e) { - System.out.println("Error: " + e); -} -``` - - -### removeObject(String bucketName, Iterable objectNames) - -`public Iterable> removeObject(String bucketName, Iterable objectNames)` - -删除多个对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#removeObject-java.lang.String-java.lang.String-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectNames`` | _Iterable_ | 含有要删除的多个object名称的迭代器对象。 | - -|返回值类型 | 异常 | -|:--- |:--- | -| ``Iterable>``:an iterator of Result DeleteError. | _None_ | - - - -__示例__ - - -```java -List objectNames = new LinkedList(); -objectNames.add("my-objectname1"); -objectNames.add("my-objectname2"); -objectNames.add("my-objectname3"); -try { - // 删除my-bucketname里的多个对象 - for (Result errorResult: minioClient.removeObject("my-bucketname", objectNames)) { - DeleteError error = errorResult.get(); - System.out.println("Failed to remove '" + error.objectName() + "'. Error:" + error.message()); - } -} catch (MinioException e) { - System.out.println("Error: " + e); -} -``` - - -### removeIncompleteUpload(String bucketName, String objectName) - -`public void removeIncompleteUpload(String bucketName, String objectName)` - -删除一个未完整上传的对象。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#removeIncompleteUpload-java.lang.String-java.lang.String-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| None | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``NoResponseException`` : 服务器无响应。 | -| | ``IOException`` : 连接异常。 | -| | ``org.xmlpull.v1.XmlPullParserException`` : 解析返回的XML异常。 | -| | ``ErrorResponseException`` : 执行失败异常。 | -| | ``InternalException`` : 内部错误。 | - - -__示例__ - - -```java -try { - // 从存储桶中删除名为myobject的未完整上传的对象。 - minioClient.removeIncompleteUpload("mybucket", "myobject"); - System.out.println("successfully removed all incomplete upload session of my-bucketname/my-objectname"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - -## 4. Presigned操作 - - -### presignedGetObject(String bucketName, String objectName, Integer expires) -`public String presignedGetObject(String bucketName, String objectName, Integer expires)` - -生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#presignedGetObject-java.lang.String-java.lang.String-java.lang.Integer-) - - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``expiry`` | _Integer_ | 失效时间(以秒为单位),默认是7天,不得大于七天。 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``String`` : string contains URL to download the object. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``InvalidKeyException`` : 不合法的access key或者secret key。 | -| | ``IOException`` : 连接异常。 | -| | ``NoSuchAlgorithmException`` : 找不到相应的签名算法。 | -| | ``InvalidExpiresRangeException`` : presigned URL已经过期了。 | - - -__示例__ - - -```java -try { - String url = minioClient.presignedGetObject("mybucket", "myobject", 60 * 60 * 24); - System.out.println(url); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### presignedPutObject(String bucketName, String objectName, Integer expires) - -`public String presignedPutObject(String bucketName, String objectName, Integer expires)` - -生成一个给HTTP PUT请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#presignedPutObject-java.lang.String-java.lang.String-java.lang.Integer-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``bucketName`` | _String_ | 存储桶名称。 | -| ``objectName`` | _String_ | 存储桶里的对象名称。 | -| ``expiry`` | _Integer_ | 失效时间(以秒为单位),默认是7天,不得大于七天。 | - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``String`` : string contains URL to download the object. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``InvalidKeyException`` : 不合法的access key或者secret key。 | -| | ``IOException`` : 连接异常。 | -| | ``NoSuchAlgorithmException`` : 找不到相应的签名算法。 | -| | ``InvalidExpiresRangeException`` : presigned URL已经过期了。 | - - -__示例__ - -```java -try { - String url = minioClient.presignedPutObject("mybucket", "myobject", 60 * 60 * 24); - System.out.println(url); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -} -``` - - -### presignedPostPolicy(PostPolicy policy) - -`public Map presignedPostPolicy(PostPolicy policy)` - -允许给POST请求的presigned URL设置策略,比如接收对象上传的存储桶名称的策略,key名称前缀,过期策略。 - -[查看 Javadoc](http://minio.github.io/minio-java/io/minio/MinioClient.html#presignedPostPolicy-io.minio.PostPolicy-) - -__参数__ - - -|参数 | 类型 | 描述 | -|:--- |:--- |:--- | -| ``policy`` | _PostPolicy_ | 对象的post策略 | - - -| 返回值类型 | 异常 | -|:--- |:--- | -| ``Map``: Map of strings to construct form-data. | 异常列表: | -| | ``InvalidBucketNameException`` : 不合法的存储桶名称。 | -| | ``InvalidKeyException`` : 不合法的access key或者secret key。 | -| | ``IOException`` : 连接异常。 | -| | ``NoSuchAlgorithmException`` : 找不到相应的签名算法。 | - - - -__示例__ - -```java -try { - PostPolicy policy = new PostPolicy("mybucket", "myobject", - DateTime.now().plusDays(7)); - policy.setContentType("image/png"); - Map formData = minioClient.presignedPostPolicy(policy); - System.out.print("curl -X POST "); - for (Map.Entry entry : formData.entrySet()) { - System.out.print(" -F " + entry.getKey() + "=" + entry.getValue()); - } - System.out.println(" -F file=@/tmp/userpic.png https://play.min.io/mybucket"); -} catch(MinioException e) { - System.out.println("Error occurred: " + e); -``` - -## 5. 了解更多 - -- [创建属于你的照片API服务示例](https://github.com/minio/minio-java-rest-example) -- [完整的JavaDoc](http://minio.github.io/minio-java/) diff --git a/docs/zh_CN/CONTRIBUTING.md b/docs/zh_CN/CONTRIBUTING.md deleted file mode 100644 index 93f856b7d..000000000 --- a/docs/zh_CN/CONTRIBUTING.md +++ /dev/null @@ -1,9 +0,0 @@ -# 贡献者指南 -* Fork minio-java. -* 创建你的分支 (`$ git checkout -b my-new-feature`)。 -* 敲代码,敲代码... -* Commit你的修改(`$ git commit -am 'Add some feature'`)。 -* 构建测试包 (`$ ./gradlew build`)。 -* 功能测试 (`$ ./gradlew runFunctionalTest`)。 -* Push到你的分支 (`$ git push origin my-new-feature`)。 -* 创建一个Pull Request。 diff --git a/examples/BucketExists.java b/examples/BucketExists.java index aec612a1e..c49b187e9 100644 --- a/examples/BucketExists.java +++ b/examples/BucketExists.java @@ -17,39 +17,31 @@ import io.minio.BucketExistsArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class BucketExists { /** MinioClient.bucketExists() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Check whether 'my-bucketname' exist or not. - boolean found = - minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucketname").build()); - if (found) { - System.out.println("my-bucketname exists"); - } else { - System.out.println("my-bucketname does not exist"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Check whether 'my-bucket' exist or not. + boolean found = + minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucket").build()); + if (found) { + System.out.println("my-bucket exists"); + } else { + System.out.println("my-bucket does not exist"); } } } diff --git a/examples/ComposeObject.java b/examples/ComposeObject.java index 3cad7faa2..f84a4c770 100644 --- a/examples/ComposeObject.java +++ b/examples/ComposeObject.java @@ -15,98 +15,72 @@ */ import io.minio.ComposeObjectArgs; -import io.minio.ComposeSource; import io.minio.MinioClient; import io.minio.ServerSideEncryption; -import io.minio.ServerSideEncryptionCustomerKey; +import io.minio.SourceObject; import io.minio.errors.MinioException; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import javax.crypto.spec.SecretKeySpec; public class ComposeObject { /** MinioClient.composeObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - { - // Create a ComposeSource to compose Object. - List sources = new ArrayList(); - sources.add( - ComposeSource.builder() - .bucket("my-bucketname-one") - .object("my-objectname-one") - .build()); - sources.add( - ComposeSource.builder() - .bucket("my-bucketname-two") - .object("my-objectname-two") - .build()); + { + // Create a SourceObject to compose Object. + List sources = new ArrayList(); + sources.add(SourceObject.builder().bucket("my-bucket-one").object("my-object-one").build()); + sources.add(SourceObject.builder().bucket("my-bucket-two").object("my-object-two").build()); - minioClient.composeObject( - ComposeObjectArgs.builder() - .bucket("my-destination-bucket") - .object("my-destination-object") - .sources(sources) - .build()); - System.out.println("Object Composed successfully"); - } - - { - ServerSideEncryptionCustomerKey srcSsec = - new ServerSideEncryptionCustomerKey( - new SecretKeySpec( - "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8), "AES")); + minioClient.composeObject( + ComposeObjectArgs.builder() + .bucket("my-destination-bucket") + .object("my-destination-object") + .sources(sources) + .build()); + System.out.println("Object Composed successfully"); + } - ServerSideEncryption sse = - new ServerSideEncryptionCustomerKey( - new SecretKeySpec( - "12345678912345678912345678912345".getBytes(StandardCharsets.UTF_8), "AES")); + { + ServerSideEncryption.CustomerKey srcSsec = + new ServerSideEncryption.CustomerKey( + new SecretKeySpec( + "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8), "AES")); - List sources = new ArrayList(); - sources.add( - ComposeSource.builder() - .bucket("my-bucketname") - .object("my-objectname-one") - .ssec(srcSsec) - .build()); - sources.add( - ComposeSource.builder() - .bucket("my-bucketname") - .object("my-objectname-two") - .ssec(srcSsec) - .build()); + ServerSideEncryption sse = + new ServerSideEncryption.CustomerKey( + new SecretKeySpec( + "12345678912345678912345678912345".getBytes(StandardCharsets.UTF_8), "AES")); - minioClient.composeObject( - ComposeObjectArgs.builder() - .bucket("my-destination-bucket") - .object("my-destination-object") - .sources(sources) - .sse(sse) - .build()); - System.out.println("Object Composed successfully"); - } + List sources = new ArrayList(); + sources.add( + SourceObject.builder().bucket("my-bucket").object("my-object-one").ssec(srcSsec).build()); + sources.add( + SourceObject.builder().bucket("my-bucket").object("my-object-two").ssec(srcSsec).build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + minioClient.composeObject( + ComposeObjectArgs.builder() + .bucket("my-destination-bucket") + .object("my-destination-object") + .sources(sources) + .sse(sse) + .build()); + System.out.println("Object Composed successfully"); } } } diff --git a/examples/CopyObject.java b/examples/CopyObject.java index 6b6508f2a..8ede00fc8 100644 --- a/examples/CopyObject.java +++ b/examples/CopyObject.java @@ -16,14 +16,10 @@ */ import io.minio.CopyObjectArgs; -import io.minio.CopySource; import io.minio.MinioClient; import io.minio.ServerSideEncryption; -import io.minio.ServerSideEncryptionCustomerKey; -import io.minio.ServerSideEncryptionKms; -import io.minio.ServerSideEncryptionS3; +import io.minio.SourceObject; import io.minio.errors.MinioException; -import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.HashMap; @@ -33,172 +29,151 @@ public class CopyObject { /** MinioClient.copyObject() example. */ public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + throws InvalidKeyException, MinioException, NoSuchAlgorithmException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); - Map myContext = new HashMap<>(); - myContext.put("key1", "value1"); - ServerSideEncryption sseKms = new ServerSideEncryptionKms("Key-Id", myContext); + Map myContext = new HashMap<>(); + myContext.put("key1", "value1"); + ServerSideEncryption sseKms = new ServerSideEncryption.KMS("Key-Id", myContext); - ServerSideEncryption sseS3 = new ServerSideEncryptionS3(); + ServerSideEncryption sseS3 = new ServerSideEncryption.S3(); - Map headers = new HashMap<>(); - headers.put("Content-Type", "application/json"); - headers.put("x-amz-meta-my-project", "Project One"); + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + headers.put("x-amz-meta-my-project", "Project One"); - String etag = "9855d05ab7a1cfd5ea304f0547c24496"; + String etag = "9855d05ab7a1cfd5ea304f0547c24496"; - { - // Create object "my-objectname" in bucket "my-bucketname" by copying from object - // "my-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-objectname") - .build()) - .build()); - System.out.println( - "my-source-bucketname/my-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } + { + // Create object "my-object" in bucket "my-bucket" by copying from object + // "my-object" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder().bucket("my-source-bucketname").object("my-object").build()) + .build()); + System.out.println( + "my-source-bucketname/my-object copied " + "to my-bucket/my-object successfully"); + } - { - // Create object "my-objectname" in bucket "my-bucketname" by copying from object - // "my-source-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-source-objectname") - .build()) - .build()); - System.out.println( - "my-source-bucketname/my-source-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } + { + // Create object "my-object" in bucket "my-bucket" by copying from object + // "my-source-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder() + .bucket("my-source-bucketname") + .object("my-source-objectname") + .build()) + .build()); + System.out.println( + "my-source-bucketname/my-source-objectname copied " + + "to my-bucket/my-object successfully"); + } - { - // Create object "my-objectname" in bucket "my-bucketname" with SSE-KMS server-side - // encryption by copying from object "my-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-objectname") - .build()) - .sse(sseKms) // Replace with actual key. - .build()); - System.out.println( - "my-source-bucketname/my-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } + { + // Create object "my-object" in bucket "my-bucket" with SSE-KMS server-side + // encryption by copying from object "my-object" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder().bucket("my-source-bucketname").object("my-object").build()) + .sse(sseKms) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-object copied " + "to my-bucket/my-object successfully"); + } - { - // Create object "my-objectname" in bucket "my-bucketname" with SSE-S3 server-side - // encryption by copying from object "my-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-objectname") - .build()) - .sse(sseS3) // Replace with actual key. - .build()); - System.out.println( - "my-source-bucketname/my-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } + { + // Create object "my-object" in bucket "my-bucket" with SSE-S3 server-side + // encryption by copying from object "my-object" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder().bucket("my-source-bucketname").object("my-object").build()) + .sse(sseS3) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-object copied " + "to my-bucket/my-object successfully"); + } - { - // Create object "my-objectname" in bucket "my-bucketname" with SSE-C server-side encryption - // by copying from object "my-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-objectname") - .build()) - .sse(ssec) // Replace with actual key. - .build()); - System.out.println( - "my-source-bucketname/my-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } + { + // Create object "my-object" in bucket "my-bucket" with SSE-C server-side encryption + // by copying from object "my-object" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder().bucket("my-source-bucketname").object("my-object").build()) + .sse(ssec) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-object copied " + "to my-bucket/my-object successfully"); + } - { - // Create object "my-objectname" in bucket "my-bucketname" by copying from SSE-C encrypted - // object "my-source-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-source-objectname") - .ssec(ssec) // Replace with actual key. - .build()) - .build()); - System.out.println( - "my-source-bucketname/my-source-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } + { + // Create object "my-object" in bucket "my-bucket" by copying from SSE-C encrypted + // object "my-source-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder() + .bucket("my-source-bucketname") + .object("my-source-objectname") + .ssec(ssec) // Replace with actual key. + .build()) + .build()); + System.out.println( + "my-source-bucketname/my-source-objectname copied " + + "to my-bucket/my-object successfully"); + } - { - // Create object "my-objectname" in bucket "my-bucketname" with custom headers conditionally - // by copying from object "my-objectname" in bucket "my-source-bucketname". - minioClient.copyObject( - CopyObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .source( - CopySource.builder() - .bucket("my-source-bucketname") - .object("my-objectname") - .matchETag(etag) // Replace with actual etag. - .build()) - .headers(headers) // Replace with actual headers. - .build()); - System.out.println( - "my-source-bucketname/my-objectname copied " - + "to my-bucketname/my-objectname successfully"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + { + // Create object "my-object" in bucket "my-bucket" with custom headers conditionally + // by copying from object "my-object" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .source( + SourceObject.builder() + .bucket("my-source-bucketname") + .object("my-object") + .matchETag(etag) // Replace with actual etag. + .build()) + .headers(headers) // Replace with actual headers. + .build()); + System.out.println( + "my-source-bucketname/my-object copied " + "to my-bucket/my-object successfully"); } } } diff --git a/examples/DeleteBucketCors.java b/examples/DeleteBucketCors.java index 86990ab43..62d0fdb50 100644 --- a/examples/DeleteBucketCors.java +++ b/examples/DeleteBucketCors.java @@ -17,33 +17,25 @@ import io.minio.DeleteBucketCorsArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketCors { /** MinioClient.deleteBucketCors() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteBucketCors(DeleteBucketCorsArgs.builder().bucket("my-bucketname").build()); - System.out.println("Bucket CORS configuration deleted successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteBucketCors(DeleteBucketCorsArgs.builder().bucket("my-bucket").build()); + System.out.println("Bucket CORS configuration deleted successfully"); } } diff --git a/examples/DeleteBucketEncryption.java b/examples/DeleteBucketEncryption.java index 004b7a3ff..d23667962 100644 --- a/examples/DeleteBucketEncryption.java +++ b/examples/DeleteBucketEncryption.java @@ -17,34 +17,26 @@ import io.minio.DeleteBucketEncryptionArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketEncryption { /** MinioClient.deleteBucketEncryption() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteBucketEncryption( - DeleteBucketEncryptionArgs.builder().bucket("my-bucketname").build()); - System.out.println("Encryption configuration of my-bucketname is removed successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteBucketEncryption( + DeleteBucketEncryptionArgs.builder().bucket("my-bucket").build()); + System.out.println("Encryption configuration of my-bucket is removed successfully"); } } diff --git a/examples/DeleteBucketLifecycle.java b/examples/DeleteBucketLifecycle.java index d9c234e01..2aacd91a1 100644 --- a/examples/DeleteBucketLifecycle.java +++ b/examples/DeleteBucketLifecycle.java @@ -17,34 +17,26 @@ import io.minio.DeleteBucketLifecycleArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketLifecycle { /** MinioClient.DeleteBucketLifecycle() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Pass blank as life cycle in setBucketLifecycle method. - minioClient.deleteBucketLifecycle( - DeleteBucketLifecycleArgs.builder().bucket("my-bucketName").build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Pass blank as life cycle in setBucketLifecycle method. + minioClient.deleteBucketLifecycle( + DeleteBucketLifecycleArgs.builder().bucket("my-bucketName").build()); } } diff --git a/examples/DeleteBucketNotification.java b/examples/DeleteBucketNotification.java index d8d0ca2ee..8b754941b 100644 --- a/examples/DeleteBucketNotification.java +++ b/examples/DeleteBucketNotification.java @@ -17,34 +17,26 @@ import io.minio.DeleteBucketNotificationArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketNotification { /** MinioClient.removeAllBucketNotification() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteBucketNotification( - DeleteBucketNotificationArgs.builder().bucket("my-bucketname").build()); - System.out.println("Removed all bucket notification"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteBucketNotification( + DeleteBucketNotificationArgs.builder().bucket("my-bucket").build()); + System.out.println("Removed all bucket notification"); } } diff --git a/examples/DeleteBucketPolicy.java b/examples/DeleteBucketPolicy.java index 25137db09..e037db756 100644 --- a/examples/DeleteBucketPolicy.java +++ b/examples/DeleteBucketPolicy.java @@ -17,34 +17,25 @@ import io.minio.DeleteBucketPolicyArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketPolicy { /** MinioClient.deleteBucketPolicy() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteBucketPolicy( - DeleteBucketPolicyArgs.builder().bucket("my-bucketname").build()); - System.out.println("Bucket policy is deleted successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket("my-bucket").build()); + System.out.println("Bucket policy is deleted successfully"); } } diff --git a/examples/DeleteBucketReplication.java b/examples/DeleteBucketReplication.java index 685858772..1ccc9187d 100644 --- a/examples/DeleteBucketReplication.java +++ b/examples/DeleteBucketReplication.java @@ -17,33 +17,25 @@ import io.minio.DeleteBucketReplicationArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketReplication { /** MinioClient.deleteBucketReplication() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteBucketReplication( - DeleteBucketReplicationArgs.builder().bucket("my-bucketname").build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteBucketReplication( + DeleteBucketReplicationArgs.builder().bucket("my-bucket").build()); } } diff --git a/examples/DeleteBucketTags.java b/examples/DeleteBucketTags.java index 106475f5f..ed7e57d68 100644 --- a/examples/DeleteBucketTags.java +++ b/examples/DeleteBucketTags.java @@ -17,33 +17,25 @@ import io.minio.DeleteBucketTagsArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteBucketTags { /** MinioClient.deleteBucketTags() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket("my-bucketname").build()); - System.out.println("Bucket tags deleted successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket("my-bucket").build()); + System.out.println("Bucket tags deleted successfully"); } } diff --git a/examples/DeleteObjectLockConfiguration.java b/examples/DeleteObjectLockConfiguration.java index bb0fe6c87..2ec7fd4a6 100644 --- a/examples/DeleteObjectLockConfiguration.java +++ b/examples/DeleteObjectLockConfiguration.java @@ -17,35 +17,27 @@ import io.minio.DeleteObjectLockConfigurationArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteObjectLockConfiguration { /** MinioClient.deleteObjectLockConfiguration() exanple. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteObjectLockConfiguration( - DeleteObjectLockConfigurationArgs.builder().bucket("my-lock-enabled-bucketname").build()); + minioClient.deleteObjectLockConfiguration( + DeleteObjectLockConfigurationArgs.builder().bucket("my-lock-enabled-bucketname").build()); - System.out.println("Object-lock configuration is deleted successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + System.out.println("Object-lock configuration is deleted successfully"); } } diff --git a/examples/DeleteObjectTags.java b/examples/DeleteObjectTags.java index 9a0c342b3..272a57190 100644 --- a/examples/DeleteObjectTags.java +++ b/examples/DeleteObjectTags.java @@ -17,34 +17,26 @@ import io.minio.DeleteObjectTagsArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DeleteObjectTags { /** MinioClient.deleteObjectTags() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.deleteObjectTags( - DeleteObjectTagsArgs.builder().bucket("my-bucketname").object("my-objectname").build()); - System.out.println("Object tags deleted successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.deleteObjectTags( + DeleteObjectTagsArgs.builder().bucket("my-bucket").object("my-object").build()); + System.out.println("Object tags deleted successfully"); } } diff --git a/examples/DisableObjectLegalHold.java b/examples/DisableObjectLegalHold.java index 668ca8a6c..292797239 100644 --- a/examples/DisableObjectLegalHold.java +++ b/examples/DisableObjectLegalHold.java @@ -16,39 +16,27 @@ import io.minio.DisableObjectLegalHoldArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class DisableObjectLegalHold { /** MinioClient.disableObjectLegalHold() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, IllegalArgumentException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Disable object legal hold. - minioClient.disableObjectLegalHold( - DisableObjectLegalHoldArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .build()); - System.out.println("Legal hold disabled on object successfully "); - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Disable object legal hold. + minioClient.disableObjectLegalHold( + DisableObjectLegalHoldArgs.builder().bucket("my-bucket").object("my-object").build()); + System.out.println("Legal hold disabled on object successfully "); } } diff --git a/examples/DownloadObject.java b/examples/DownloadObject.java index f357842d0..cf6f4e683 100644 --- a/examples/DownloadObject.java +++ b/examples/DownloadObject.java @@ -16,9 +16,8 @@ import io.minio.DownloadObjectArgs; import io.minio.MinioClient; -import io.minio.ServerSideEncryptionCustomerKey; +import io.minio.ServerSideEncryption; import io.minio.errors.MinioException; -import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.KeyGenerator; @@ -26,51 +25,47 @@ public class DownloadObject { /** MinioClient.getObject() example. */ public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + throws InvalidKeyException, MinioException, NoSuchAlgorithmException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - { - // Download 'my-objectname' from 'my-bucketname' to 'my-filename' - minioClient.downloadObject( - DownloadObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .filename("my-filename") - .build()); - System.out.println("my-objectname is successfully downloaded to my-filename"); - } + { + // Download 'my-object' from 'my-bucket' to 'my-filename' + minioClient.downloadObject( + DownloadObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .filename("my-filename") + .build()); + System.out.println("my-object is successfully downloaded to my-filename"); + } - { - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); - // Download SSE-C encrypted 'my-objectname' from 'my-bucketname' to 'my-filename' - minioClient.downloadObject( - DownloadObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .filename("my-filename") - .ssec(ssec) // Replace with same SSE-C used at the time of upload. - .build()); - System.out.println("my-objectname is successfully downloaded to my-filename"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Download SSE-C encrypted 'my-object' from 'my-bucket' to 'my-filename' + minioClient.downloadObject( + DownloadObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .filename("my-filename") + .ssec(ssec) // Replace with same SSE-C used at the time of upload. + .build()); + System.out.println("my-object is successfully downloaded to my-filename"); } } } diff --git a/examples/EnableObjectLegalHold.java b/examples/EnableObjectLegalHold.java index c96f50fce..0bc1c11cf 100644 --- a/examples/EnableObjectLegalHold.java +++ b/examples/EnableObjectLegalHold.java @@ -16,40 +16,32 @@ import io.minio.EnableObjectLegalHoldArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class EnableObjectLegalHold { /** MinioClient.enableObjectLegalHold() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, IllegalArgumentException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Enable object legal hold. - minioClient.enableObjectLegalHold( - EnableObjectLegalHoldArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .versionId("object-versionId") - .build()); + // Enable object legal hold. + minioClient.enableObjectLegalHold( + EnableObjectLegalHoldArgs.builder() + .bucket("my-bucket") + .object("my-object") + .versionId("object-versionId") + .build()); - System.out.println("Legal hold enabled on object successfully "); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + System.out.println("Legal hold enabled on object successfully "); } } diff --git a/examples/GetBucketCors.java b/examples/GetBucketCors.java index 713f8fc07..0ad2f5952 100644 --- a/examples/GetBucketCors.java +++ b/examples/GetBucketCors.java @@ -18,34 +18,26 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.CORSConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketCors { /** MinioClient.getBucketCors() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - CORSConfiguration config = - minioClient.getBucketCors(GetBucketCorsArgs.builder().bucket("my-bucketname").build()); - System.out.println("Bucket CORS configuration rules: " + config.rules()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + CORSConfiguration config = + minioClient.getBucketCors(GetBucketCorsArgs.builder().bucket("my-bucket").build()); + System.out.println("Bucket CORS configuration rules: " + config.rules()); } } diff --git a/examples/GetBucketEncryption.java b/examples/GetBucketEncryption.java index a00b2c110..ab46b9c66 100644 --- a/examples/GetBucketEncryption.java +++ b/examples/GetBucketEncryption.java @@ -19,42 +19,34 @@ import io.minio.errors.MinioException; import io.minio.messages.SseAlgorithm; import io.minio.messages.SseConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketEncryption { /** MinioClient.getBucketEncryption() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - SseConfiguration config = - minioClient.getBucketEncryption( - GetBucketEncryptionArgs.builder().bucket("my-bucketname").build()); - if (config.rule() != null) { - System.out.println("Rule SSE algorithm: " + config.rule().sseAlgorithm()); - if (config.rule().sseAlgorithm() == SseAlgorithm.AWS_KMS) { - System.out.println("Rule KMS master key ID: " + config.rule().kmsMasterKeyId()); - } - } else { - System.out.println("No rule is set in SSE configuration."); + SseConfiguration config = + minioClient.getBucketEncryption( + GetBucketEncryptionArgs.builder().bucket("my-bucket").build()); + if (config.rule() != null) { + System.out.println("Rule SSE algorithm: " + config.rule().sseAlgorithm()); + if (config.rule().sseAlgorithm() == SseAlgorithm.AWS_KMS) { + System.out.println("Rule KMS master key ID: " + config.rule().kmsMasterKeyId()); } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + } else { + System.out.println("No rule is set in SSE configuration."); } } } diff --git a/examples/GetBucketLifecycle.java b/examples/GetBucketLifecycle.java index 5e6cd0d49..f5ab5106f 100644 --- a/examples/GetBucketLifecycle.java +++ b/examples/GetBucketLifecycle.java @@ -18,35 +18,27 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.LifecycleConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketLifecycle { /** MinioClient.getBucketLifecycle() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - LifecycleConfiguration config = - minioClient.getBucketLifecycle( - GetBucketLifecycleArgs.builder().bucket("my-bucketName").build()); - System.out.println("Lifecycle configuration is " + config); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + LifecycleConfiguration config = + minioClient.getBucketLifecycle( + GetBucketLifecycleArgs.builder().bucket("my-bucketName").build()); + System.out.println("Lifecycle configuration is " + config); } } diff --git a/examples/GetBucketNotification.java b/examples/GetBucketNotification.java index 3755ab80e..03d29ce8a 100644 --- a/examples/GetBucketNotification.java +++ b/examples/GetBucketNotification.java @@ -18,35 +18,27 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.NotificationConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketNotification { /** MinioClient.getBucketNotification() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - NotificationConfiguration config = - minioClient.getBucketNotification( - GetBucketNotificationArgs.builder().bucket("my-bucketname").build()); - System.out.println(config); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + NotificationConfiguration config = + minioClient.getBucketNotification( + GetBucketNotificationArgs.builder().bucket("my-bucket").build()); + System.out.println(config); } } diff --git a/examples/GetBucketPolicy.java b/examples/GetBucketPolicy.java index d049a0804..6601bbfbb 100644 --- a/examples/GetBucketPolicy.java +++ b/examples/GetBucketPolicy.java @@ -17,35 +17,26 @@ import io.minio.GetBucketPolicyArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketPolicy { /** MinioClient.getBucketPolicy() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - String policy = - minioClient.getBucketPolicy( - GetBucketPolicyArgs.builder().bucket("my-bucketname").build()); - System.out.println("Current policy: " + policy); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + String policy = + minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket("my-bucket").build()); + System.out.println("Current policy: " + policy); } } diff --git a/examples/GetBucketReplication.java b/examples/GetBucketReplication.java index 36e506734..47571052b 100644 --- a/examples/GetBucketReplication.java +++ b/examples/GetBucketReplication.java @@ -18,35 +18,27 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.ReplicationConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketReplication { /** MinioClient.getBucketReplication() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - ReplicationConfiguration config = - minioClient.getBucketReplication( - GetBucketReplicationArgs.builder().bucket("my-bucketname").build()); - System.out.println(" Replication configuration is: " + config); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + ReplicationConfiguration config = + minioClient.getBucketReplication( + GetBucketReplicationArgs.builder().bucket("my-bucket").build()); + System.out.println(" Replication configuration is: " + config); } } diff --git a/examples/GetBucketTags.java b/examples/GetBucketTags.java index 93b77cb76..a2168a970 100644 --- a/examples/GetBucketTags.java +++ b/examples/GetBucketTags.java @@ -18,34 +18,25 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.Tags; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketTags { /** MinioClient.getBucketTags() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - Tags tags = - minioClient.getBucketTags(GetBucketTagsArgs.builder().bucket("my-bucketname").build()); - System.out.println("Bucket tags: " + tags.get()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + Tags tags = minioClient.getBucketTags(GetBucketTagsArgs.builder().bucket("my-bucket").build()); + System.out.println("Bucket tags: " + tags.get()); } } diff --git a/examples/GetBucketVersioning.java b/examples/GetBucketVersioning.java index e34682957..8155d77e8 100644 --- a/examples/GetBucketVersioning.java +++ b/examples/GetBucketVersioning.java @@ -18,35 +18,27 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.VersioningConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetBucketVersioning { /** MinioClient.getBucketVersioning() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - VersioningConfiguration config = - minioClient.getBucketVersioning( - GetBucketVersioningArgs.builder().bucket("my-bucketname").build()); - System.out.println("Versioning on bucket 'my-bucketname' is " + config.status()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + VersioningConfiguration config = + minioClient.getBucketVersioning( + GetBucketVersioningArgs.builder().bucket("my-bucket").build()); + System.out.println("Versioning on bucket 'my-bucket' is " + config.status()); } } diff --git a/examples/GetObject.java b/examples/GetObject.java index d052219b5..11da0f2fa 100644 --- a/examples/GetObject.java +++ b/examples/GetObject.java @@ -20,44 +20,37 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObject { /** MinioClient.getObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws IOException, MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Get input stream to have content of 'my-objectname' from 'my-bucketname' - InputStream stream = - minioClient.getObject( - GetObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + // Get input stream to have content of 'my-object' from 'my-bucket' + InputStream stream = + minioClient.getObject( + GetObjectArgs.builder().bucket("my-bucket").object("my-object").build()); - // Read the input stream and print to the console till EOF. - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); - } - - // Close the input stream. - stream.close(); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Read the input stream and print to the console till EOF. + byte[] buf = new byte[16384]; + int bytesRead; + while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { + System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); } + + // Close the input stream. + stream.close(); } } diff --git a/examples/GetObjectAcl.java b/examples/GetObjectAcl.java index 97a481649..22eaa3fd3 100644 --- a/examples/GetObjectAcl.java +++ b/examples/GetObjectAcl.java @@ -18,35 +18,27 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.AccessControlPolicy; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObjectAcl { /** MinioClient.getObjectAcl() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - AccessControlPolicy policy = - minioClient.getObjectAcl( - GetObjectAclArgs.builder().bucket("my-bucketname").object("my-objectname").build()); - System.out.println("Access control policy: " + policy); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + AccessControlPolicy policy = + minioClient.getObjectAcl( + GetObjectAclArgs.builder().bucket("my-bucket").object("my-object").build()); + System.out.println("Access control policy: " + policy); } } diff --git a/examples/GetObjectAttributes.java b/examples/GetObjectAttributes.java index b2a03e426..eb8a7b8f3 100644 --- a/examples/GetObjectAttributes.java +++ b/examples/GetObjectAttributes.java @@ -18,42 +18,32 @@ import io.minio.GetObjectAttributesResponse; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObjectAttributes { /** MinioClient.getObjectAttributes() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - GetObjectAttributesResponse response = - minioClient.getObjectAttributes( - GetObjectAttributesArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .objectAttributes( - new String[] { - "ETag", "Checksum", "ObjectParts", "StorageClass", "ObjectSize" - }) - .build()); - System.out.println("Response: " + response); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + GetObjectAttributesResponse response = + minioClient.getObjectAttributes( + GetObjectAttributesArgs.builder() + .bucket("my-bucket") + .object("my-object") + .objectAttributes( + new String[] {"ETag", "Checksum", "ObjectParts", "StorageClass", "ObjectSize"}) + .build()); + System.out.println("Response: " + response); } } diff --git a/examples/GetObjectLockConfiguration.java b/examples/GetObjectLockConfiguration.java index 165b25026..39c83f6dd 100644 --- a/examples/GetObjectLockConfiguration.java +++ b/examples/GetObjectLockConfiguration.java @@ -18,40 +18,30 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.ObjectLockConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObjectLockConfiguration { /** MinioClient.getObjectLockConfiguration() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - ObjectLockConfiguration config = - minioClient.getObjectLockConfiguration( - GetObjectLockConfigurationArgs.builder() - .bucket("my-lock-enabled-bucketname") - .build()); + ObjectLockConfiguration config = + minioClient.getObjectLockConfiguration( + GetObjectLockConfigurationArgs.builder().bucket("my-lock-enabled-bucketname").build()); - System.out.println("Object-lock configuration of bucket"); - System.out.println("Mode: " + config.mode()); - System.out.println("Duration: " + config.duration()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + System.out.println("Object-lock configuration of bucket"); + System.out.println("Mode: " + config.mode()); + System.out.println("Duration: " + config.duration()); } } diff --git a/examples/GetObjectProgressBar.java b/examples/GetObjectProgressBar.java index 33ef9041b..eeeb8636d 100644 --- a/examples/GetObjectProgressBar.java +++ b/examples/GetObjectProgressBar.java @@ -27,66 +27,55 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObjectProgressBar { /** MinioClient.getObjectProgressBar() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws IOException, MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Check whether the object exists using statObject(). If the object is not found, - // statObject() throws an exception. It means that the object exists when statObject() - // execution is successful. + // Check whether the object exists using statObject(). If the object is not found, + // statObject() throws an exception. It means that the object exists when statObject() + // execution is successful. - // Get object stat information. - StatObjectResponse stat = - minioClient.statObject( - StatObjectArgs.builder() - .bucket("testbucket") - .object("resumes/4.original.pdf") - .build()); + // Get object stat information. + StatObjectResponse stat = + minioClient.statObject( + StatObjectArgs.builder().bucket("testbucket").object("resumes/4.original.pdf").build()); - // Get input stream to have content of 'my-objectname' from 'my-bucketname' - InputStream is = - new ProgressStream( - "Downloading .. ", - stat.size(), - minioClient.getObject( - GetObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build())); + // Get input stream to have content of 'my-object' from 'my-bucket' + InputStream is = + new ProgressStream( + "Downloading .. ", + stat.size(), + minioClient.getObject( + GetObjectArgs.builder().bucket("my-bucket").object("my-object").build())); - Path path = Paths.get("my-filename"); - OutputStream os = Files.newOutputStream(path, StandardOpenOption.CREATE); + Path path = Paths.get("my-filename"); + OutputStream os = Files.newOutputStream(path, StandardOpenOption.CREATE); - long bytesWritten = ByteStreams.copy(is, os); - is.close(); - os.close(); + long bytesWritten = ByteStreams.copy(is, os); + is.close(); + os.close(); - if (bytesWritten != stat.size()) { - throw new IOException( - path - + ": unexpected data written. expected = " - + stat.size() - + ", written = " - + bytesWritten); - } - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + if (bytesWritten != stat.size()) { + throw new IOException( + path + + ": unexpected data written. expected = " + + stat.size() + + ", written = " + + bytesWritten); } } } diff --git a/examples/GetObjectResume.java b/examples/GetObjectResume.java index ff9984cc6..3b857f5db 100644 --- a/examples/GetObjectResume.java +++ b/examples/GetObjectResume.java @@ -3,6 +3,8 @@ import io.minio.MinioClient; import io.minio.StatObjectArgs; import io.minio.StatObjectResponse; +import io.minio.errors.MinioException; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; @@ -11,21 +13,21 @@ import java.nio.file.StandardOpenOption; public class GetObjectResume { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws IOException, MinioException { MinioClient minioClient = MinioClient.builder() .endpoint("https://play.min.io") .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") .build(); - String filename = "my-objectname"; + String filename = "my-object"; Path path = Paths.get(filename); long fileSize = 0; if (Files.exists(path)) fileSize = Files.size(path); StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); if (fileSize == stat.size()) { // Already fully downloaded. @@ -33,14 +35,14 @@ public static void main(String[] args) throws Exception { } if (fileSize > stat.size()) { - throw new Exception("stored file size is greater than object size"); + throw new IOException("stored file size is greater than object size"); } InputStream stream = minioClient.getObject( GetObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") + .bucket("my-bucket") + .object("my-object") .offset(fileSize) .build()); diff --git a/examples/GetObjectRetention.java b/examples/GetObjectRetention.java index 8c2a3a249..c7e624d07 100644 --- a/examples/GetObjectRetention.java +++ b/examples/GetObjectRetention.java @@ -18,41 +18,30 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.Retention; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObjectRetention { /** MinioClient.getObjectRetention() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, IllegalArgumentException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Get object lock retention - Retention retention = - minioClient.getObjectRetention( - GetObjectRetentionArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .build()); + // Get object lock retention + Retention retention = + minioClient.getObjectRetention( + GetObjectRetentionArgs.builder().bucket("my-bucket").object("my-object").build()); - System.out.println("Mode: " + retention.mode()); - System.out.println("Retainuntil Date: " + retention.retainUntilDate()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + System.out.println("Mode: " + retention.mode()); + System.out.println("Retain until date: " + retention.retainUntilDate()); } } diff --git a/examples/GetObjectTags.java b/examples/GetObjectTags.java index c951ea824..213c15317 100644 --- a/examples/GetObjectTags.java +++ b/examples/GetObjectTags.java @@ -18,35 +18,27 @@ import io.minio.MinioClient; import io.minio.errors.MinioException; import io.minio.messages.Tags; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetObjectTags { /** MinioClient.getObjectTags() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - Tags tags = - minioClient.getObjectTags( - GetObjectTagsArgs.builder().bucket("my-bucketname").object("my-objectname").build()); - System.out.println("Object tags: " + tags.get()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + Tags tags = + minioClient.getObjectTags( + GetObjectTagsArgs.builder().bucket("my-bucket").object("my-object").build()); + System.out.println("Object tags: " + tags.get()); } } diff --git a/examples/GetPartialObject.java b/examples/GetPartialObject.java index f37cfdb40..65555f973 100644 --- a/examples/GetPartialObject.java +++ b/examples/GetPartialObject.java @@ -20,50 +20,43 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetPartialObject { /** MinioClient.getObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws IOException, MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Get input stream to have content of 'my-objectname' from 'my-bucketname' starts from - // byte position 1024 and length 4096. - InputStream stream = - minioClient.getObject( - GetObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .offset(1024L) - .length(4096L) - .build()); + // Get input stream to have content of 'my-object' from 'my-bucket' starts from + // byte position 1024 and length 4096. + InputStream stream = + minioClient.getObject( + GetObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .offset(1024L) + .length(4096L) + .build()); - // Read the input stream and print to the console till EOF. - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); - } - - // Close the input stream. - stream.close(); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Read the input stream and print to the console till EOF. + byte[] buf = new byte[16384]; + int bytesRead; + while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { + System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); } + + // Close the input stream. + stream.close(); } } diff --git a/examples/GetPresignedObjectUrl.java b/examples/GetPresignedObjectUrl.java index e154b88cb..74d9104f4 100644 --- a/examples/GetPresignedObjectUrl.java +++ b/examples/GetPresignedObjectUrl.java @@ -15,45 +15,37 @@ */ import io.minio.GetPresignedObjectUrlArgs; +import io.minio.Http; import io.minio.MinioClient; import io.minio.errors.MinioException; -import io.minio.http.Method; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class GetPresignedObjectUrl { /** MinioClient.getPresignedObjectUrl() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Get presigned URL string to delete 'my-objectname' in 'my-bucketname' and its life time - // is one day. - String url = - minioClient.getPresignedObjectUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.DELETE) - .bucket("my-bucketname") - .object("my-objectname") - .expiry(60 * 60 * 24) - .build()); - System.out.println(url); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Get presigned URL string to delete 'my-object' in 'my-bucket' and its life time + // is one day. + String url = + minioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.DELETE) + .bucket("my-bucket") + .object("my-object") + .expiry(60 * 60 * 24) + .build()); + System.out.println(url); } } diff --git a/examples/GetPresignedPostFormData.java b/examples/GetPresignedPostFormData.java index 305873577..2665c1230 100644 --- a/examples/GetPresignedPostFormData.java +++ b/examples/GetPresignedPostFormData.java @@ -19,8 +19,6 @@ import io.minio.errors.MinioException; import java.io.File; import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; import java.util.Map; import okhttp3.MultipartBody; @@ -31,72 +29,67 @@ public class GetPresignedPostFormData { /** MinioClient.presignedPostPolicy() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws IOException, MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Create new post policy for 'my-bucketname' with 7 days expiry from now. - PostPolicy policy = new PostPolicy("my-bucketname", ZonedDateTime.now().plusDays(7)); + // Create new post policy for 'my-bucket' with 7 days expiry from now. + PostPolicy policy = new PostPolicy("my-bucket", ZonedDateTime.now().plusDays(7)); - // Add condition that 'key' (object name) equals to 'my-objectname'. - policy.addEqualsCondition("key", "my-objectname"); + // Add condition that 'key' (object name) equals to 'my-object'. + policy.addEqualsCondition("key", "my-object"); - // Add condition that 'Content-Type' starts with 'image/'. - policy.addStartsWithCondition("Content-Type", "image/"); + // Add condition that 'Content-Type' starts with 'image/'. + policy.addStartsWithCondition("Content-Type", "image/"); - // Add condition that 'content-length-range' is between 64kiB to 10MiB. - policy.addContentLengthRangeCondition(64 * 1024, 10 * 1024 * 1024); + // Add condition that 'content-length-range' is between 64kiB to 10MiB. + policy.addContentLengthRangeCondition(64 * 1024, 10 * 1024 * 1024); - Map formData = minioClient.getPresignedPostFormData(policy); + Map formData = minioClient.getPresignedPostFormData(policy); - // Upload an image using POST object with form-data. - MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); - multipartBuilder.setType(MultipartBody.FORM); - for (Map.Entry entry : formData.entrySet()) { - multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue()); - } - multipartBuilder.addFormDataPart("key", "my-objectname"); - multipartBuilder.addFormDataPart("Content-Type", "image/png"); + // Upload an image using POST object with form-data. + MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); + multipartBuilder.setType(MultipartBody.FORM); + for (Map.Entry entry : formData.entrySet()) { + multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue()); + } + multipartBuilder.addFormDataPart("key", "my-object"); + multipartBuilder.addFormDataPart("Content-Type", "image/png"); - // "file" must be added at last. - multipartBuilder.addFormDataPart( - "file", "my-objectname", RequestBody.create(new File("Pictures/avatar.png"), null)); + // "file" must be added at last. + multipartBuilder.addFormDataPart( + "file", "my-object", RequestBody.create(new File("Pictures/avatar.png"), null)); - Request request = - new Request.Builder() - .url("https://play.min.io/my-bucketname") - .post(multipartBuilder.build()) - .build(); - OkHttpClient httpClient = new OkHttpClient().newBuilder().build(); - Response response = httpClient.newCall(request).execute(); - if (response.isSuccessful()) { - System.out.println("Pictures/avatar.png is uploaded successfully using POST object"); - } else { - System.out.println("Failed to upload Pictures/avatar.png"); - } + Request request = + new Request.Builder() + .url("https://play.min.io/my-bucket") + .post(multipartBuilder.build()) + .build(); + OkHttpClient httpClient = new OkHttpClient().newBuilder().build(); + Response response = httpClient.newCall(request).execute(); + if (response.isSuccessful()) { + System.out.println("Pictures/avatar.png is uploaded successfully using POST object"); + } else { + System.out.println("Failed to upload Pictures/avatar.png"); + } - // Print curl command usage to upload file /tmp/userpic.jpg. - System.out.print("curl -X POST "); - for (Map.Entry entry : formData.entrySet()) { - System.out.print(" -F " + entry.getKey() + "=" + entry.getValue()); - } - System.out.print(" -F key=my-objectname -F Content-Type=image/jpg"); - System.out.println(" -F file=@/tmp/userpic.jpg https://play.min.io/my-bucketname"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Print curl command usage to upload file /tmp/userpic.jpg. + System.out.print("curl -X POST "); + for (Map.Entry entry : formData.entrySet()) { + System.out.print(" -F " + entry.getKey() + "=" + entry.getValue()); } + System.out.print(" -F key=my-object -F Content-Type=image/jpg"); + System.out.println(" -F file=@/tmp/userpic.jpg https://play.min.io/my-bucket"); } } diff --git a/examples/IsObjectLegalHoldEnabled.java b/examples/IsObjectLegalHoldEnabled.java index fe760df2d..1a7ef1b16 100644 --- a/examples/IsObjectLegalHoldEnabled.java +++ b/examples/IsObjectLegalHoldEnabled.java @@ -18,74 +18,56 @@ import io.minio.IsObjectLegalHoldEnabledArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class IsObjectLegalHoldEnabled { /** MinioClient.isObjectLegalHoldEnabled() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, IllegalArgumentException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Enable object legal hold. - minioClient.enableObjectLegalHold( - EnableObjectLegalHoldArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .versionId("object-versionId") - .build()); - System.out.println("Legal hold enabled on object successfully "); + // Enable object legal hold. + minioClient.enableObjectLegalHold( + EnableObjectLegalHoldArgs.builder() + .bucket("my-bucket") + .object("my-object") + .versionId("object-versionId") + .build()); + System.out.println("Legal hold enabled on object successfully "); - boolean status = - minioClient.isObjectLegalHoldEnabled( - IsObjectLegalHoldEnabledArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .build()); + boolean status = + minioClient.isObjectLegalHoldEnabled( + IsObjectLegalHoldEnabledArgs.builder().bucket("my-bucket").object("my-object").build()); - if (status) { - System.out.println("Legal hold is on"); - } else { - System.out.println("Legal hold is off"); - } - - // Disable object legal hold. - minioClient.disableObjectLegalHold( - DisableObjectLegalHoldArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .build()); + if (status) { + System.out.println("Legal hold is on"); + } else { + System.out.println("Legal hold is off"); + } - status = - minioClient.isObjectLegalHoldEnabled( - IsObjectLegalHoldEnabledArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .build()); - System.out.println("Legal hold disabled on object successfully "); + // Disable object legal hold. + minioClient.disableObjectLegalHold( + DisableObjectLegalHoldArgs.builder().bucket("my-bucket").object("my-object").build()); - if (status) { - System.out.println("Legal hold is on"); - } else { - System.out.println("Legal hold is off"); - } + status = + minioClient.isObjectLegalHoldEnabled( + IsObjectLegalHoldEnabledArgs.builder().bucket("my-bucket").object("my-object").build()); + System.out.println("Legal hold disabled on object successfully "); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + if (status) { + System.out.println("Legal hold is on"); + } else { + System.out.println("Legal hold is off"); } } } diff --git a/examples/ListBuckets.java b/examples/ListBuckets.java index f0e15263d..62e3a5b6c 100644 --- a/examples/ListBuckets.java +++ b/examples/ListBuckets.java @@ -18,41 +18,34 @@ import io.minio.MinioClient; import io.minio.Result; import io.minio.errors.MinioException; -import io.minio.messages.Bucket; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import io.minio.messages.ListAllMyBucketsResult; public class ListBuckets { /** MinioClient.listBuckets() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // List buckets we have atleast read access. - Iterable> results = minioClient.listBuckets(ListBucketsArgs.builder().build()); - for (Result result : results) { - Bucket bucket = result.get(); - System.out.println( - String.format( - "Bucket: %s, Region: %s, CreationDate: %s", - bucket.name(), bucket.bucketRegion(), bucket.creationDate())); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // List buckets we have at least read access. + Iterable> results = + minioClient.listBuckets(ListBucketsArgs.builder().build()); + for (Result result : results) { + ListAllMyBucketsResult.Bucket bucket = result.get(); + System.out.println( + String.format( + "Bucket: %s, Region: %s, CreationDate: %s", + bucket.name(), bucket.bucketRegion(), bucket.creationDate())); } } } diff --git a/examples/ListObjects.java b/examples/ListObjects.java index 3d4b03fb8..ae3abfa64 100644 --- a/examples/ListObjects.java +++ b/examples/ListObjects.java @@ -19,98 +19,90 @@ import io.minio.Result; import io.minio.errors.MinioException; import io.minio.messages.Item; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class ListObjects { /** MinioClient.listObjects() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - { - // Lists objects information. - Iterable> results = - minioClient.listObjects(ListObjectsArgs.builder().bucket("my-bucketname").build()); + { + // Lists objects information. + Iterable> results = + minioClient.listObjects(ListObjectsArgs.builder().bucket("my-bucket").build()); - for (Result result : results) { - Item item = result.get(); - System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName()); - } + for (Result result : results) { + Item item = result.get(); + System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName()); } + } - { - // Lists objects information recursively. - Iterable> results = - minioClient.listObjects( - ListObjectsArgs.builder().bucket("my-bucketname").recursive(true).build()); + { + // Lists objects information recursively. + Iterable> results = + minioClient.listObjects( + ListObjectsArgs.builder().bucket("my-bucket").recursive(true).build()); - for (Result result : results) { - Item item = result.get(); - System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName()); - } + for (Result result : results) { + Item item = result.get(); + System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName()); } + } - { - // Lists maximum 100 objects information those names starts with 'E' and after - // 'ExampleGuide.pdf'. - Iterable> results = - minioClient.listObjects( - ListObjectsArgs.builder() - .bucket("my-bucketname") - .startAfter("ExampleGuide.pdf") - .prefix("E") - .maxKeys(100) - .build()); + { + // Lists maximum 100 objects information those names starts with 'E' and after + // 'ExampleGuide.pdf'. + Iterable> results = + minioClient.listObjects( + ListObjectsArgs.builder() + .bucket("my-bucket") + .startAfter("ExampleGuide.pdf") + .prefix("E") + .maxKeys(100) + .build()); - for (Result result : results) { - Item item = result.get(); - System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName()); - } + for (Result result : results) { + Item item = result.get(); + System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName()); } + } - { - // Lists maximum 100 objects information with version those names starts with 'E' and after - // 'ExampleGuide.pdf'. - Iterable> results = - minioClient.listObjects( - ListObjectsArgs.builder() - .bucket("my-bucketname") - .startAfter("ExampleGuide.pdf") - .prefix("E") - .maxKeys(100) - .includeVersions(true) - .build()); + { + // Lists maximum 100 objects information with version those names starts with 'E' and after + // 'ExampleGuide.pdf'. + Iterable> results = + minioClient.listObjects( + ListObjectsArgs.builder() + .bucket("my-bucket") + .startAfter("ExampleGuide.pdf") + .prefix("E") + .maxKeys(100) + .includeVersions(true) + .build()); - for (Result result : results) { - Item item = result.get(); - System.out.println( - item.lastModified() - + "\t" - + item.size() - + "\t" - + item.objectName() - + " [" - + item.versionId() - + "]"); - } + for (Result result : results) { + Item item = result.get(); + System.out.println( + item.lastModified() + + "\t" + + item.size() + + "\t" + + item.objectName() + + " [" + + item.versionId() + + "]"); } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); } } } diff --git a/examples/ListenBucketNotification.java b/examples/ListenBucketNotification.java index d0b5bc80b..d7e138bfe 100644 --- a/examples/ListenBucketNotification.java +++ b/examples/ListenBucketNotification.java @@ -19,49 +19,42 @@ import io.minio.MinioClient; import io.minio.Result; import io.minio.errors.MinioException; -import io.minio.messages.Event; import io.minio.messages.NotificationRecords; import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class ListenBucketNotification { /** MinioClient.listenBucketNotification() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - String[] events = {"s3:ObjectCreated:*", "s3:ObjectAccessed:*"}; - try (CloseableIterator> ci = - minioClient.listenBucketNotification( - ListenBucketNotificationArgs.builder() - .bucket("bucketName") - .prefix("") - .suffix("") - .events(events) - .build())) { - while (ci.hasNext()) { - NotificationRecords records = ci.next().get(); - Event event = records.events().get(0); - System.out.println(event.bucketName() + "/" + event.objectName() + " has been created"); - } - } catch (IOException e) { - System.out.println("Error occurred: " + e); + String[] events = {"s3:ObjectCreated:*", "s3:ObjectAccessed:*"}; + try (CloseableIterator> ci = + minioClient.listenBucketNotification( + ListenBucketNotificationArgs.builder() + .bucket("bucketName") + .prefix("") + .suffix("") + .events(events) + .build())) { + while (ci.hasNext()) { + NotificationRecords records = ci.next().get(); + NotificationRecords.Event event = records.events().get(0); + System.out.println( + event.bucket().name() + "/" + event.object().key() + " has been created"); } - } catch (MinioException e) { + } catch (IOException e) { System.out.println("Error occurred: " + e); } } diff --git a/examples/MakeBucket.java b/examples/MakeBucket.java index 967dc730f..9ae49cf56 100644 --- a/examples/MakeBucket.java +++ b/examples/MakeBucket.java @@ -18,57 +18,48 @@ import io.minio.MakeBucketArgs; import io.minio.MinioClient; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class MakeBucket { /** MinioClient.makeBucket() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Create bucket 'my-bucketname' if it doesn`t exist. - if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucketname").build())) { - minioClient.makeBucket(MakeBucketArgs.builder().bucket("my-bucketname").build()); - System.out.println("my-bucketname is created successfully"); - } + // Create bucket 'my-bucket' if it does not exist. + if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucket").build())) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket("my-bucket").build()); + System.out.println("my-bucket is created successfully"); + } - // Create bucket 'my-bucketname-in-eu' in 'eu-west-1' region if it doesn't exist. - if (!minioClient.bucketExists( - BucketExistsArgs.builder().bucket("my-bucketname-in-eu").build())) { - minioClient.makeBucket( - MakeBucketArgs.builder().bucket("my-bucketname-in-eu").region("eu-west-1").build()); - System.out.println("my-bucketname-in-eu is created successfully"); - } + // Create bucket 'my-bucket-in-eu' in 'eu-west-1' region if it does not exist. + if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucket-in-eu").build())) { + minioClient.makeBucket( + MakeBucketArgs.builder().bucket("my-bucket-in-eu").region("eu-west-1").build()); + System.out.println("my-bucket-in-eu is created successfully"); + } - // Create bucket 'my-bucketname-in-eu-with-object-lock' in 'eu-west-1' with object lock - // functionality enabled. - if (!minioClient.bucketExists( - BucketExistsArgs.builder().bucket("my-bucketname-in-eu-with-object-lock").build())) { - minioClient.makeBucket( - MakeBucketArgs.builder() - .bucket("my-bucketname-in-eu-with-object-lock") - .region("eu-west-1") - .objectLock(true) - .build()); - System.out.println("my-bucketname-in-eu-with-object-lock is created successfully"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Create bucket 'my-bucket-in-eu-with-object-lock' in 'eu-west-1' with object lock + // functionality enabled. + if (!minioClient.bucketExists( + BucketExistsArgs.builder().bucket("my-bucket-in-eu-with-object-lock").build())) { + minioClient.makeBucket( + MakeBucketArgs.builder() + .bucket("my-bucket-in-eu-with-object-lock") + .region("eu-west-1") + .objectLock(true) + .build()); + System.out.println("my-bucket-in-eu-with-object-lock is created successfully"); } } } diff --git a/examples/MinioClientWithAssumeRoleProvider.java b/examples/MinioClientWithAssumeRoleProvider.java index fa2b30edc..45a1c4aa6 100644 --- a/examples/MinioClientWithAssumeRoleProvider.java +++ b/examples/MinioClientWithAssumeRoleProvider.java @@ -19,9 +19,10 @@ import io.minio.StatObjectResponse; import io.minio.credentials.AssumeRoleProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; public class MinioClientWithAssumeRoleProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { Provider provider = new AssumeRoleProvider( "https://play.minio.io:9000/", // STS endpoint usually point to MinIO server. @@ -44,7 +45,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithAwsConfigProvider.java b/examples/MinioClientWithAwsConfigProvider.java index 1040a8f5b..87fa1b1f3 100644 --- a/examples/MinioClientWithAwsConfigProvider.java +++ b/examples/MinioClientWithAwsConfigProvider.java @@ -19,9 +19,10 @@ import io.minio.StatObjectResponse; import io.minio.credentials.AwsConfigProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; public class MinioClientWithAwsConfigProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { Provider provider = new AwsConfigProvider(null, null); MinioClient minioClient = @@ -33,7 +34,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithCertificateIdentityProvider.java b/examples/MinioClientWithCertificateIdentityProvider.java index 82429317a..1954c5882 100644 --- a/examples/MinioClientWithCertificateIdentityProvider.java +++ b/examples/MinioClientWithCertificateIdentityProvider.java @@ -19,11 +19,12 @@ import io.minio.StatObjectResponse; import io.minio.credentials.CertificateIdentityProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; public class MinioClientWithCertificateIdentityProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { // STS endpoint usually point to MinIO server. String stsEndpoint = "https://STS-HOST:STS-PORT/"; @@ -39,7 +40,8 @@ public static void main(String[] args) throws Exception { // CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); // // Certificate serverCertificate = null; - // try (FileInputStream fis = new FileInputStream("/home/bala/.minio/certs/public.crt")) { + // try (FileInputStream fis = + // Files.newInputStream(Paths.get("/home/bala/.minio/certs/public.crt"))) { // serverCertificate = certificateFactory.generateCertificate(fis); // } // @@ -61,7 +63,8 @@ public static void main(String[] args) throws Exception { // PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey); // // Certificate certificateChain = null; - // try (FileInputStream fis = new FileInputStream("/home/bala/.minio/certs/CAs/client1.crt")) { + // try (FileInputStream fis = + // Files.newInputStream(Paths.get("/home/bala/.minio/certs/CAs/client1.crt"))) { // certificateChain = certificateFactory.generateCertificate(fis); // } // @@ -102,7 +105,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithChainedProvider.java b/examples/MinioClientWithChainedProvider.java index 84af8c095..64ae532b4 100644 --- a/examples/MinioClientWithChainedProvider.java +++ b/examples/MinioClientWithChainedProvider.java @@ -21,9 +21,10 @@ import io.minio.credentials.ChainedProvider; import io.minio.credentials.MinioEnvironmentProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; public class MinioClientWithChainedProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { Provider provider = new ChainedProvider(new AwsEnvironmentProvider(), new MinioEnvironmentProvider()); @@ -36,7 +37,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithClientGrantsProvider.java b/examples/MinioClientWithClientGrantsProvider.java index 43ec46152..8636dc3be 100644 --- a/examples/MinioClientWithClientGrantsProvider.java +++ b/examples/MinioClientWithClientGrantsProvider.java @@ -24,6 +24,7 @@ import io.minio.credentials.ClientGrantsProvider; import io.minio.credentials.Jwt; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; import java.io.IOException; import java.security.ProviderException; import java.util.Objects; @@ -62,7 +63,7 @@ static Jwt getJwt( } } - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { // IDP endpoint. String idpEndpoint = "https://IDP-HOST:IDP-PORT/auth/realms/master/protocol/openid-connect/token"; @@ -112,7 +113,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithIamAwsProvider.java b/examples/MinioClientWithIamAwsProvider.java index ade161a4a..508281bd9 100644 --- a/examples/MinioClientWithIamAwsProvider.java +++ b/examples/MinioClientWithIamAwsProvider.java @@ -19,9 +19,10 @@ import io.minio.StatObjectResponse; import io.minio.credentials.IamAwsProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; public class MinioClientWithIamAwsProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { Provider provider = new IamAwsProvider(null, null); MinioClient minioClient = @@ -33,7 +34,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithLdapIdentityProvider.java b/examples/MinioClientWithLdapIdentityProvider.java index b07e9f279..397cb5c03 100644 --- a/examples/MinioClientWithLdapIdentityProvider.java +++ b/examples/MinioClientWithLdapIdentityProvider.java @@ -19,9 +19,10 @@ import io.minio.StatObjectResponse; import io.minio.credentials.LdapIdentityProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; public class MinioClientWithLdapIdentityProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { // STS endpoint usually point to MinIO server. String stsEndpoint = "http://STS-HOST:STS-PORT/"; @@ -42,7 +43,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithMinioClientConfigProvider.java b/examples/MinioClientWithMinioClientConfigProvider.java index 5bc58730a..ea0214ec0 100644 --- a/examples/MinioClientWithMinioClientConfigProvider.java +++ b/examples/MinioClientWithMinioClientConfigProvider.java @@ -19,9 +19,10 @@ import io.minio.StatObjectResponse; import io.minio.credentials.MinioClientConfigProvider; import io.minio.credentials.Provider; +import io.minio.errors.MinioException; public class MinioClientWithMinioClientConfigProvider { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { Provider provider = new MinioClientConfigProvider(null, null); MinioClient minioClient = @@ -33,7 +34,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/MinioClientWithWebIdentityProvider.java b/examples/MinioClientWithWebIdentityProvider.java index 80550ee68..10ed3983a 100644 --- a/examples/MinioClientWithWebIdentityProvider.java +++ b/examples/MinioClientWithWebIdentityProvider.java @@ -24,6 +24,7 @@ import io.minio.credentials.Jwt; import io.minio.credentials.Provider; import io.minio.credentials.WebIdentityProvider; +import io.minio.errors.MinioException; import java.io.IOException; import java.security.ProviderException; import java.util.Objects; @@ -66,7 +67,7 @@ static Jwt getJwt( } } - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws MinioException { // IDP endpoint. String idpEndpoint = "https://IDP-HOST:IDP-PORT/auth/realms/master/protocol/openid-connect/token"; @@ -108,7 +109,7 @@ public static void main(String[] args) throws Exception { // Get information of an object. StatObjectResponse stat = minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); System.out.println(stat); } } diff --git a/examples/PresignedGetObject.java b/examples/PresignedGetObject.java index cf9c889d2..af31143ab 100644 --- a/examples/PresignedGetObject.java +++ b/examples/PresignedGetObject.java @@ -15,45 +15,37 @@ */ import io.minio.GetPresignedObjectUrlArgs; +import io.minio.Http; import io.minio.MinioClient; import io.minio.errors.MinioException; -import io.minio.http.Method; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class PresignedGetObject { /** MinioClient.presignedGetObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Get presigned URL string to download 'my-objectname' in 'my-bucketname' and its life time - // is one day. - String url = - minioClient.getPresignedObjectUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket("my-bucketname") - .object("my-objectname") - .expiry(60 * 60 * 24) - .build()); - System.out.println(url); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Get presigned URL string to download 'my-object' in 'my-bucket' and its life time + // is one day. + String url = + minioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.GET) + .bucket("my-bucket") + .object("my-object") + .expiry(60 * 60 * 24) + .build()); + System.out.println(url); } } diff --git a/examples/PresignedPutObject.java b/examples/PresignedPutObject.java index e231de21e..716f0f0b6 100644 --- a/examples/PresignedPutObject.java +++ b/examples/PresignedPutObject.java @@ -15,52 +15,44 @@ */ import io.minio.GetPresignedObjectUrlArgs; +import io.minio.Http; import io.minio.MinioClient; import io.minio.errors.MinioException; -import io.minio.http.Method; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; public class PresignedPutObject { /** MinioClient.presignedPutObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Get presigned URL string to upload 'my-objectname' in 'my-bucketname' - // with response-content-type as application/json and its life time is - // one day. - Map reqParams = new HashMap(); - reqParams.put("response-content-type", "application/json"); + // Get presigned URL string to upload 'my-object' in 'my-bucket' + // with response-content-type as application/json and its life time is + // one day. + Map reqParams = new HashMap(); + reqParams.put("response-content-type", "application/json"); - String url = - minioClient.getPresignedObjectUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) - .bucket("my-bucketname") - .object("my-objectname") - .expiry(60 * 60 * 24) - .extraQueryParams(reqParams) - .build()); - System.out.println(url); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + String url = + minioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.PUT) + .bucket("my-bucket") + .object("my-object") + .expiry(60 * 60 * 24) + .extraQueryParams(reqParams) + .build()); + System.out.println(url); } } diff --git a/examples/PutObject.java b/examples/PutObject.java index 06fdd75ef..21324bc81 100644 --- a/examples/PutObject.java +++ b/examples/PutObject.java @@ -17,12 +17,9 @@ import io.minio.MinioClient; import io.minio.PutObjectArgs; import io.minio.ServerSideEncryption; -import io.minio.ServerSideEncryptionCustomerKey; -import io.minio.ServerSideEncryptionKms; -import io.minio.ServerSideEncryptionS3; import io.minio.errors.MinioException; import java.io.ByteArrayInputStream; -import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.HashMap; @@ -32,157 +29,159 @@ public class PutObject { /** MinioClient.putObject() example. */ public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); - - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - { - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( - bais, bais.available(), -1) - .build()); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - } - - { - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Generate a new 256 bit AES key - This key must be remembered by the client. - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); - - // Create encrypted object 'my-objectname' using SSE-C in 'my-bucketname' with content from - // the input stream. - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( - bais, bais.available(), -1) - .sse(ssec) - .build()); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - } - - { - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - Map myContext = new HashMap<>(); - myContext.put("key1", "value1"); - ServerSideEncryption sseKms = new ServerSideEncryptionKms("Key-Id", myContext); - - // Create encrypted object 'my-objectname' using SSE-KMS in 'my-bucketname' with content - // from the input stream. - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( - bais, bais.available(), -1) - .sse(sseKms) - .build()); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - } - - { - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - ServerSideEncryption sseS3 = new ServerSideEncryptionS3(); - - // Create encrypted object 'my-objectname' using SSE-S3 in 'my-bucketname' with content - // from the input stream. - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( - bais, bais.available(), -1) - .sse(sseS3) - .build()); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - } - - { - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Create headers - Map headers = new HashMap<>(); - // Add custom content type - headers.put("Content-Type", "application/octet-stream"); - // Add storage class - headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); - - // Add custom/user metadata - Map userMetadata = new HashMap<>(); - userMetadata.put("My-Project", "Project One"); - - // Create object 'my-objectname' with user metadata and other properties in 'my-bucketname' - // with content - // from the input stream. - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( - bais, bais.available(), -1) - .headers(headers) - .userMetadata(userMetadata) - .build()); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - } - - { - // Create object name ending with '/' (mostly called folder or directory). - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("path/to/").stream( - new ByteArrayInputStream(new byte[] {}), 1, -1) - .build()); - System.out.println("path/to/ is created successfully"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + throws InvalidKeyException, MinioException, NoSuchAlgorithmException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); + + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); + + // Create some content for the object. + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 1000; i++) { + builder.append( + "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); + builder.append("(29 letters)\n"); + builder.append( + "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); + builder.append("(31 letters)\n"); + builder.append( + "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); + builder.append("NASAs Space Shuttle. (32 letters)\n"); + builder.append( + "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic" + + " Card. "); + builder.append("(39 letters)\n"); + builder.append( + "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity" + + " "); + builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); + builder.append( + "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for" + + " Mac "); + builder.append("computers after System 7.\n"); + builder.append( + "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack!" + + " my "); + builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); + builder.append("---\n"); + } + byte[] data = builder.toString().getBytes(StandardCharsets.UTF_8); + + { + // Create object 'my-object' in 'my-bucket' with content from byte array. + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .data(data, data.length) + .build()); + System.out.println("my-object is uploaded successfully"); + } + + { + // Create object 'my-object' in 'my-bucket' with content from input stream in parallel. + minioClient.putObject( + PutObjectArgs.builder().bucket("my-bucket").object("my-object").stream( + new ByteArrayInputStream(data), (long) data.length, null) + .parallelUploads(4) + .build()); + System.out.println("my-object is uploaded successfully"); + } + + { + // Generate a new 256 bit AES key - This key must be remembered by the client. + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); + + // Create encrypted object 'my-object' using SSE-C in 'my-bucket' with content from + // byte array. + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .data(data, data.length) + .sse(ssec) + .build()); + System.out.println("my-object is uploaded successfully"); + } + + { + Map myContext = new HashMap<>(); + myContext.put("key1", "value1"); + ServerSideEncryption sseKms = new ServerSideEncryption.KMS("Key-Id", myContext); + + // Create encrypted object 'my-object' using SSE-KMS in 'my-bucket' with content + // from byte array. + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .data(data, data.length) + .sse(sseKms) + .build()); + System.out.println("my-object is uploaded successfully"); + } + + { + ServerSideEncryption sseS3 = new ServerSideEncryption.S3(); + + // Create encrypted object 'my-object' using SSE-S3 in 'my-bucket' with content + // from byte array. + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .data(data, data.length) + .sse(sseS3) + .build()); + System.out.println("my-object is uploaded successfully"); + } + + { + // Create headers + Map headers = new HashMap<>(); + // Add custom content type + headers.put("Content-Type", "application/octet-stream"); + // Add storage class + headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); + + // Add custom/user metadata + Map userMetadata = new HashMap<>(); + userMetadata.put("My-Project", "Project One"); + + // Create object 'my-object' with user metadata and other properties in 'my-bucket' + // with content from byte array. + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .data(data, data.length) + .headers(headers) + .userMetadata(userMetadata) + .build()); + System.out.println("my-object is uploaded successfully"); + } + + { + // Create object name ending with '/' (mostly called folder or directory). + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("path/to/") + .data(new byte[0], 0) + .build()); + System.out.println("path/to/ is created successfully"); } } } diff --git a/examples/PutObjectFanOut.java b/examples/PutObjectFanOut.java index ca9c2dfea..e807ee664 100644 --- a/examples/PutObjectFanOut.java +++ b/examples/PutObjectFanOut.java @@ -20,50 +20,42 @@ import io.minio.PutObjectFanOutResponse; import io.minio.errors.MinioException; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; public class PutObjectFanOut { /** MinioClient.putObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - PutObjectFanOutResponse response = - minioClient.putObjectFanOut( - PutObjectFanOutArgs.builder().bucket("my-bucketname").stream( - new ByteArrayInputStream("somedata".getBytes(StandardCharsets.UTF_8)), 8) - .entries( - Arrays.asList( - new PutObjectFanOutEntry[] { - PutObjectFanOutEntry.builder().key("fan-out.0").build(), - PutObjectFanOutEntry.builder().key("fan-out.1").tags(map).build() - })) - .build()); - System.out.println("response: " + response); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + PutObjectFanOutResponse response = + minioClient.putObjectFanOut( + PutObjectFanOutArgs.builder().bucket("my-bucket").stream( + new ByteArrayInputStream("somedata".getBytes(StandardCharsets.UTF_8)), 8) + .entries( + Arrays.asList( + new PutObjectFanOutEntry[] { + PutObjectFanOutEntry.builder().key("fan-out.0").build(), + PutObjectFanOutEntry.builder().key("fan-out.1").tags(map).build() + })) + .build()); + System.out.println("response: " + response); } } diff --git a/examples/PutObjectProgressBar.java b/examples/PutObjectProgressBar.java index 557a20c15..4101a7ff7 100644 --- a/examples/PutObjectProgressBar.java +++ b/examples/PutObjectProgressBar.java @@ -18,17 +18,14 @@ import io.minio.PutObjectArgs; import io.minio.errors.MinioException; import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import java.nio.file.Files; +import java.nio.file.Paths; public class PutObjectProgressBar { /** MinioClient.putObjectProgressBar() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException { + public static void main(String[] args) throws IOException, MinioException { /* play.min.io for test and development. */ MinioClient minioClient = MinioClient.builder() @@ -43,17 +40,17 @@ public static void main(String[] args) // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") // .build(); - String objectName = "my-objectname"; - String bucketName = "my-bucketname"; + String objectName = "my-object"; + String bucketName = "my-bucket"; - File file = new File("my-filename"); InputStream pis = - new BufferedInputStream(new ProgressStream("Uploading... ", new FileInputStream(file))); + new BufferedInputStream( + new ProgressStream("Uploading... ", Files.newInputStream(Paths.get("my-filename")))); minioClient.putObject( PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - pis, pis.available(), -1) + pis, (long) pis.available(), null) .build()); pis.close(); - System.out.println("my-objectname is uploaded successfully"); + System.out.println("my-object is uploaded successfully"); } } diff --git a/examples/PutObjectUiProgressBar.java b/examples/PutObjectUiProgressBar.java index 655eae64d..ecb3bf546 100644 --- a/examples/PutObjectUiProgressBar.java +++ b/examples/PutObjectUiProgressBar.java @@ -21,11 +21,10 @@ import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import java.nio.file.Files; +import java.nio.file.Paths; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.ProgressMonitorInputStream; @@ -52,12 +51,11 @@ public void go() { } /** - * uploadFile(fileName) uploads to configured object storage upon reading a local file, while + * uploadFile(filename) uploads to configured object storage upon reading a local file, while * asynchronously updating the progress bar UI as well. This function is involed when user clicks * on the UI */ - private void uploadFile(String fileName) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException { + private void uploadFile(String filename) throws MinioException { /* play.min.io for test and development. */ MinioClient minioClient = MinioClient.builder() @@ -72,17 +70,18 @@ private void uploadFile(String fileName) // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") // .build(); - File file = new File(fileName); - try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) { + File file = new File(filename); + try (BufferedInputStream bis = + new BufferedInputStream(Files.newInputStream(Paths.get(filename)))) { ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(this, "Uploading... " + file.getAbsolutePath(), bis); pmis.getProgressMonitor().setMillisToPopup(10); minioClient.putObject( - PutObjectArgs.builder().bucket("bank").object("my-objectname").stream( - pmis, pmis.available(), -1) + PutObjectArgs.builder().bucket("bank").object("my-object").stream( + pmis, (long) pmis.available(), null) .build()); - System.out.println("my-objectname is uploaded successfully"); + System.out.println("my-object is uploaded successfully"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/examples/RemoveBucket.java b/examples/RemoveBucket.java index 3b08c3064..2eadd7d6f 100644 --- a/examples/RemoveBucket.java +++ b/examples/RemoveBucket.java @@ -18,41 +18,33 @@ import io.minio.MinioClient; import io.minio.RemoveBucketArgs; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class RemoveBucket { /** MinioClient.removeBucket() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Remove bucket 'my-bucketname' if it exists. - // This operation will only work if your bucket is empty. - boolean found = - minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucketname").build()); - if (found) { - minioClient.removeBucket(RemoveBucketArgs.builder().bucket("my-bucketname").build()); - System.out.println("my-bucketname is removed successfully"); - } else { - System.out.println("my-bucketname does not exist"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + // Remove bucket 'my-bucket' if it exists. + // This operation will only work if your bucket is empty. + boolean found = + minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucket").build()); + if (found) { + minioClient.removeBucket(RemoveBucketArgs.builder().bucket("my-bucket").build()); + System.out.println("my-bucket is removed successfully"); + } else { + System.out.println("my-bucket does not exist"); } } } diff --git a/examples/RemoveObject.java b/examples/RemoveObject.java index 3cc804509..c2cd327a5 100644 --- a/examples/RemoveObject.java +++ b/examples/RemoveObject.java @@ -17,51 +17,43 @@ import io.minio.MinioClient; import io.minio.RemoveObjectArgs; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class RemoveObject { /** MinioClient.removeObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Remove object. - minioClient.removeObject( - RemoveObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); + // Remove object. + minioClient.removeObject( + RemoveObjectArgs.builder().bucket("my-bucket").object("my-object").build()); - // Remove versioned object. - minioClient.removeObject( - RemoveObjectArgs.builder() - .bucket("my-bucketname") - .object("my-versioned-objectname") - .versionId("my-versionid") - .build()); + // Remove versioned object. + minioClient.removeObject( + RemoveObjectArgs.builder() + .bucket("my-bucket") + .object("my-versioned-objectname") + .versionId("my-versionid") + .build()); - // Remove versioned object bypassing Governance mode. - minioClient.removeObject( - RemoveObjectArgs.builder() - .bucket("my-bucketname") - .object("my-versioned-objectname") - .versionId("my-versionid") - .bypassGovernanceMode(true) - .build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Remove versioned object bypassing Governance mode. + minioClient.removeObject( + RemoveObjectArgs.builder() + .bucket("my-bucket") + .object("my-versioned-objectname") + .versionId("my-versionid") + .bypassGovernanceMode(true) + .build()); } } diff --git a/examples/RemoveObjects.java b/examples/RemoveObjects.java index 11827c3a7..8e37a8a49 100644 --- a/examples/RemoveObjects.java +++ b/examples/RemoveObjects.java @@ -18,47 +18,38 @@ import io.minio.RemoveObjectsArgs; import io.minio.Result; import io.minio.errors.MinioException; -import io.minio.messages.DeleteError; -import io.minio.messages.DeleteObject; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import io.minio.messages.DeleteRequest; +import io.minio.messages.DeleteResult; import java.util.LinkedList; import java.util.List; public class RemoveObjects { /** MinioClient.removeObject() example removing multiple objects. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - List objects = new LinkedList<>(); - objects.add(new DeleteObject("my-objectname1")); - objects.add(new DeleteObject("my-objectname2")); - objects.add(new DeleteObject("my-objectname3")); - Iterable> results = - minioClient.removeObjects( - RemoveObjectsArgs.builder().bucket("my-bucketname").objects(objects).build()); - for (Result result : results) { - DeleteError error = result.get(); - System.out.println( - "Error in deleting object " + error.objectName() + "; " + error.message()); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + List objects = new LinkedList<>(); + objects.add(new DeleteRequest.Object("my-object1")); + objects.add(new DeleteRequest.Object("my-object2")); + objects.add(new DeleteRequest.Object("my-object3")); + Iterable> results = + minioClient.removeObjects( + RemoveObjectsArgs.builder().bucket("my-bucket").objects(objects).build()); + for (Result result : results) { + DeleteResult.Error error = result.get(); + System.out.println("Error in deleting object " + error.objectName() + "; " + error.message()); } } } diff --git a/examples/RestoreObject.java b/examples/RestoreObject.java index 44589e788..5eceff4f9 100644 --- a/examples/RestoreObject.java +++ b/examples/RestoreObject.java @@ -18,47 +18,39 @@ import io.minio.RestoreObjectArgs; import io.minio.errors.MinioException; import io.minio.messages.RestoreRequest; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class RestoreObject { /** MinioClient.restoreObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Restore object. - minioClient.restoreObject( - RestoreObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .request(new RestoreRequest(null, null, null, null, null, null)) - .build()); + // Restore object. + minioClient.restoreObject( + RestoreObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .request(new RestoreRequest(null, null, null, null, null, null)) + .build()); - // Restore versioned object. - minioClient.restoreObject( - RestoreObjectArgs.builder() - .bucket("my-bucketname") - .object("my-versioned-objectname") - .versionId("my-versionid") - .request(new RestoreRequest(null, null, null, null, null, null)) - .build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Restore versioned object. + minioClient.restoreObject( + RestoreObjectArgs.builder() + .bucket("my-bucket") + .object("my-versioned-objectname") + .versionId("my-versionid") + .request(new RestoreRequest(null, null, null, null, null, null)) + .build()); } } diff --git a/examples/SelectObjectContent.java b/examples/SelectObjectContent.java index 247a08a1a..ab4a4ebdb 100644 --- a/examples/SelectObjectContent.java +++ b/examples/SelectObjectContent.java @@ -19,77 +19,70 @@ import io.minio.SelectObjectContentArgs; import io.minio.SelectResponseStream; import io.minio.errors.MinioException; -import io.minio.messages.FileHeaderInfo; import io.minio.messages.InputSerialization; import io.minio.messages.OutputSerialization; -import io.minio.messages.QuoteFields; import io.minio.messages.Stats; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class SelectObjectContent { /** MinioClient.getObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws IOException, MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - byte[] data = - ("Year,Make,Model,Description,Price\n" - + "1997,Ford,E350,\"ac, abs, moon\",3000.00\n" - + "1999,Chevy,\"Venture \"\"Extended Edition\"\"\",\"\",4900.00\n" - + "1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00\n" - + "1996,Jeep,Grand Cherokee,\"MUST SELL!\n" - + "air, moon roof, loaded\",4799.00\n") - .getBytes(StandardCharsets.UTF_8); - ByteArrayInputStream bais = new ByteArrayInputStream(data); - minioClient.putObject( - PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( - bais, data.length, -1) - .build()); + byte[] data = + ("Year,Make,Model,Description,Price\n" + + "1997,Ford,E350,\"ac, abs, moon\",3000.00\n" + + "1999,Chevy,\"Venture \"\"Extended Edition\"\"\",\"\",4900.00\n" + + "1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00\n" + + "1996,Jeep,Grand Cherokee,\"MUST SELL!\n" + + "air, moon roof, loaded\",4799.00\n") + .getBytes(StandardCharsets.UTF_8); + minioClient.putObject( + PutObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .data(data, data.length) + .build()); - String sqlExpression = "select * from S3Object"; - InputSerialization is = - new InputSerialization(null, false, null, null, FileHeaderInfo.USE, null, null, null); - OutputSerialization os = - new OutputSerialization(null, null, null, QuoteFields.ASNEEDED, null); + String sqlExpression = "select * from S3Object"; + InputSerialization is = + InputSerialization.newCSV( + null, false, null, null, InputSerialization.FileHeaderInfo.USE, null, null, null); + OutputSerialization os = + OutputSerialization.newCSV( + null, null, null, OutputSerialization.QuoteFields.ASNEEDED, null); - SelectResponseStream stream = - minioClient.selectObjectContent( - SelectObjectContentArgs.builder() - .bucket("my-bucketname") - .object("my-objectName") - .sqlExpression(sqlExpression) - .inputSerialization(is) - .outputSerialization(os) - .requestProgress(true) - .build()); + SelectResponseStream stream = + minioClient.selectObjectContent( + SelectObjectContentArgs.builder() + .bucket("my-bucket") + .object("my-objectName") + .sqlExpression(sqlExpression) + .inputSerialization(is) + .outputSerialization(os) + .requestProgress(true) + .build()); - byte[] buf = new byte[512]; - int bytesRead = stream.read(buf, 0, buf.length); - System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); - Stats stats = stream.stats(); - System.out.println("bytes scanned: " + stats.bytesScanned()); - System.out.println("bytes processed: " + stats.bytesProcessed()); - System.out.println("bytes returned: " + stats.bytesReturned()); - stream.close(); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + byte[] buf = new byte[512]; + int bytesRead = stream.read(buf, 0, buf.length); + System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); + Stats stats = stream.stats(); + System.out.println("bytes scanned: " + stats.bytesScanned()); + System.out.println("bytes processed: " + stats.bytesProcessed()); + System.out.println("bytes returned: " + stats.bytesReturned()); + stream.close(); } } diff --git a/examples/SetBucketCors.java b/examples/SetBucketCors.java index 37ec1fcfc..ddba8d64e 100644 --- a/examples/SetBucketCors.java +++ b/examples/SetBucketCors.java @@ -18,58 +18,50 @@ import io.minio.SetBucketCorsArgs; import io.minio.errors.MinioException; import io.minio.messages.CORSConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.Arrays; public class SetBucketCors { /** MinioClient.setBucketCors() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - CORSConfiguration config = - new CORSConfiguration( - Arrays.asList( - new CORSConfiguration.CORSRule[] { - // Rule 1 - new CORSConfiguration.CORSRule( - Arrays.asList(new String[] {"*"}), // Allowed headers - Arrays.asList(new String[] {"PUT", "POST", "DELETE"}), // Allowed methods - Arrays.asList(new String[] {"http://www.example.com"}), // Allowed origins - Arrays.asList( - new String[] {"x-amz-server-side-encryption"}), // Expose headers - null, // ID - 3000), // Maximum age seconds - // Rule 2 - new CORSConfiguration.CORSRule( - null, // Allowed headers - Arrays.asList(new String[] {"GET"}), // Allowed methods - Arrays.asList(new String[] {"*"}), // Allowed origins - null, // Expose headers - null, // ID - null // Maximum age seconds - ) - })); + CORSConfiguration config = + new CORSConfiguration( + Arrays.asList( + new CORSConfiguration.CORSRule[] { + // Rule 1 + new CORSConfiguration.CORSRule( + Arrays.asList(new String[] {"*"}), // Allowed headers + Arrays.asList(new String[] {"PUT", "POST", "DELETE"}), // Allowed methods + Arrays.asList(new String[] {"http://www.example.com"}), // Allowed origins + Arrays.asList( + new String[] {"x-amz-server-side-encryption"}), // Expose headers + null, // ID + 3000), // Maximum age seconds + // Rule 2 + new CORSConfiguration.CORSRule( + null, // Allowed headers + Arrays.asList(new String[] {"GET"}), // Allowed methods + Arrays.asList(new String[] {"*"}), // Allowed origins + null, // Expose headers + null, // ID + null // Maximum age seconds + ) + })); - minioClient.setBucketCors( - SetBucketCorsArgs.builder().bucket("my-bucketname").config(config).build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.setBucketCors( + SetBucketCorsArgs.builder().bucket("my-bucket").config(config).build()); } } diff --git a/examples/SetBucketEncryption.java b/examples/SetBucketEncryption.java index 0956a0b05..8628227f1 100644 --- a/examples/SetBucketEncryption.java +++ b/examples/SetBucketEncryption.java @@ -18,37 +18,29 @@ import io.minio.SetBucketEncryptionArgs; import io.minio.errors.MinioException; import io.minio.messages.SseConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class SetBucketEncryption { /** MinioClient.setBucketEncryption() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - minioClient.setBucketEncryption( - SetBucketEncryptionArgs.builder() - .bucket("my-bucketname") - .config(SseConfiguration.newConfigWithSseS3Rule()) - .build()); - System.out.println("Encryption configuration of my-bucketname is set successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.setBucketEncryption( + SetBucketEncryptionArgs.builder() + .bucket("my-bucket") + .config(SseConfiguration.newConfigWithSseS3Rule()) + .build()); + System.out.println("Encryption configuration of my-bucket is set successfully"); } } diff --git a/examples/SetBucketLifecycle.java b/examples/SetBucketLifecycle.java index 2b512a5c1..f6d21ae3c 100644 --- a/examples/SetBucketLifecycle.java +++ b/examples/SetBucketLifecycle.java @@ -17,54 +17,44 @@ import io.minio.MinioClient; import io.minio.SetBucketLifecycleArgs; import io.minio.errors.MinioException; -import io.minio.messages.Expiration; +import io.minio.messages.Filter; import io.minio.messages.LifecycleConfiguration; -import io.minio.messages.LifecycleRule; -import io.minio.messages.RuleFilter; import io.minio.messages.Status; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; import java.util.LinkedList; import java.util.List; public class SetBucketLifecycle { /** MinioClient.SetBucketLifecycle() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - List rules = new LinkedList<>(); - rules.add( - new LifecycleRule( - Status.ENABLED, - null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), - "rule2", - null, - null, - null)); - LifecycleConfiguration config = new LifecycleConfiguration(rules); + List rules = new LinkedList<>(); + rules.add( + new LifecycleConfiguration.Rule( + Status.ENABLED, + null, + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), + "rule2", + null, + null, + null)); + LifecycleConfiguration config = new LifecycleConfiguration(rules); - minioClient.setBucketLifecycle( - SetBucketLifecycleArgs.builder().bucket("my-bucketname").config(config).build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.setBucketLifecycle( + SetBucketLifecycleArgs.builder().bucket("my-bucket").config(config).build()); } } diff --git a/examples/SetBucketNotification.java b/examples/SetBucketNotification.java index a3f1cf496..bc3ef744a 100644 --- a/examples/SetBucketNotification.java +++ b/examples/SetBucketNotification.java @@ -19,55 +19,47 @@ import io.minio.errors.MinioException; import io.minio.messages.EventType; import io.minio.messages.NotificationConfiguration; -import io.minio.messages.QueueConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.LinkedList; -import java.util.List; +import java.util.Arrays; public class SetBucketNotification { /** MinioClient.setBucketNotification() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - NotificationConfiguration config = new NotificationConfiguration(); + NotificationConfiguration config = + new NotificationConfiguration( + null, + Arrays.asList( + new NotificationConfiguration.QueueConfiguration[] { + // Add a new SQS configuration. + new NotificationConfiguration.QueueConfiguration( + "arn:minio:sqs::1:webhook", + null, + Arrays.asList( + new String[] { + EventType.OBJECT_CREATED_PUT.toString(), + EventType.OBJECT_CREATED_COPY.toString() + }), + new NotificationConfiguration.Filter("images", "pg")) + }), + null, + null); - // Add a new SQS configuration. - List queueConfigurationList = new LinkedList<>(); - QueueConfiguration queueConfiguration = new QueueConfiguration(); - queueConfiguration.setQueue("arn:minio:sqs::1:webhook"); - - List eventList = new LinkedList<>(); - eventList.add(EventType.OBJECT_CREATED_PUT); - eventList.add(EventType.OBJECT_CREATED_COPY); - queueConfiguration.setEvents(eventList); - queueConfiguration.setPrefixRule("images"); - queueConfiguration.setSuffixRule("pg"); - - queueConfigurationList.add(queueConfiguration); - config.setQueueConfigurationList(queueConfigurationList); - - // Set updated notification configuration. - minioClient.setBucketNotification( - SetBucketNotificationArgs.builder().bucket("my-bucketname").config(config).build()); - System.out.println("Bucket notification is set successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Set updated notification configuration. + minioClient.setBucketNotification( + SetBucketNotificationArgs.builder().bucket("my-bucket").config(config).build()); + System.out.println("Bucket notification is set successfully"); } } diff --git a/examples/SetBucketPolicy.java b/examples/SetBucketPolicy.java index 07f7b89ba..59e53a711 100644 --- a/examples/SetBucketPolicy.java +++ b/examples/SetBucketPolicy.java @@ -17,54 +17,46 @@ import io.minio.MinioClient; import io.minio.SetBucketPolicyArgs; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class SetBucketPolicy { /** MinioClient.setBucketPolicy() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - StringBuilder builder = new StringBuilder(); - builder.append("{\n"); - builder.append(" \"Statement\": [\n"); - builder.append(" {\n"); - builder.append(" \"Action\": [\n"); - builder.append(" \"s3:GetBucketLocation\",\n"); - builder.append(" \"s3:ListBucket\"\n"); - builder.append(" ],\n"); - builder.append(" \"Effect\": \"Allow\",\n"); - builder.append(" \"Principal\": \"*\",\n"); - builder.append(" \"Resource\": \"arn:aws:s3:::my-bucketname\"\n"); - builder.append(" },\n"); - builder.append(" {\n"); - builder.append(" \"Action\": \"s3:GetObject\",\n"); - builder.append(" \"Effect\": \"Allow\",\n"); - builder.append(" \"Principal\": \"*\",\n"); - builder.append(" \"Resource\": \"arn:aws:s3:::my-bucketname/myobject*\"\n"); - builder.append(" }\n"); - builder.append(" ],\n"); - builder.append(" \"Version\": \"2012-10-17\"\n"); - builder.append("}\n"); - minioClient.setBucketPolicy( - SetBucketPolicyArgs.builder().bucket("my-bucketname").config(builder.toString()).build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + StringBuilder builder = new StringBuilder(); + builder.append("{\n"); + builder.append(" \"Statement\": [\n"); + builder.append(" {\n"); + builder.append(" \"Action\": [\n"); + builder.append(" \"s3:GetBucketLocation\",\n"); + builder.append(" \"s3:ListBucket\"\n"); + builder.append(" ],\n"); + builder.append(" \"Effect\": \"Allow\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::my-bucket\"\n"); + builder.append(" },\n"); + builder.append(" {\n"); + builder.append(" \"Action\": \"s3:GetObject\",\n"); + builder.append(" \"Effect\": \"Allow\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::my-bucket/myobject*\"\n"); + builder.append(" }\n"); + builder.append(" ],\n"); + builder.append(" \"Version\": \"2012-10-17\"\n"); + builder.append("}\n"); + minioClient.setBucketPolicy( + SetBucketPolicyArgs.builder().bucket("my-bucket").config(builder.toString()).build()); } } diff --git a/examples/SetBucketReplication.java b/examples/SetBucketReplication.java index 5f35de2ce..85dc00232 100644 --- a/examples/SetBucketReplication.java +++ b/examples/SetBucketReplication.java @@ -17,16 +17,9 @@ import io.minio.MinioClient; import io.minio.SetBucketReplicationArgs; import io.minio.errors.MinioException; -import io.minio.messages.AndOperator; -import io.minio.messages.DeleteMarkerReplication; +import io.minio.messages.Filter; import io.minio.messages.ReplicationConfiguration; -import io.minio.messages.ReplicationDestination; -import io.minio.messages.ReplicationRule; -import io.minio.messages.RuleFilter; import io.minio.messages.Status; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -34,50 +27,45 @@ public class SetBucketReplication { /** MinioClient.setBucketReplication() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - Map tags = new HashMap<>(); - tags.put("key1", "value1"); - tags.put("key2", "value2"); + Map tags = new HashMap<>(); + tags.put("key1", "value1"); + tags.put("key2", "value2"); - ReplicationRule rule = - new ReplicationRule( - new DeleteMarkerReplication(Status.DISABLED), - new ReplicationDestination( - null, null, "REPLACE-WITH-ACTUAL-DESTINATION-BUCKET-ARN", null, null, null, null), - null, - new RuleFilter(new AndOperator("TaxDocs", tags)), - "rule1", - null, - 1, - null, - Status.ENABLED); + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, "REPLACE-WITH-ACTUAL-DESTINATION-BUCKET-ARN", null, null, null, null), + null, + new Filter(new Filter.And("TaxDocs", tags)), + "rule1", + null, + 1, + null, + Status.ENABLED); - List rules = new LinkedList<>(); - rules.add(rule); + List rules = new LinkedList<>(); + rules.add(rule); - ReplicationConfiguration config = - new ReplicationConfiguration("REPLACE-WITH-ACTUAL-ROLE", rules); + ReplicationConfiguration config = + new ReplicationConfiguration("REPLACE-WITH-ACTUAL-ROLE", rules); - minioClient.setBucketReplication( - SetBucketReplicationArgs.builder().bucket("my-bucketname").config(config).build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + minioClient.setBucketReplication( + SetBucketReplicationArgs.builder().bucket("my-bucket").config(config).build()); } } diff --git a/examples/SetBucketTags.java b/examples/SetBucketTags.java index 49245d9ca..0fb6f40aa 100644 --- a/examples/SetBucketTags.java +++ b/examples/SetBucketTags.java @@ -17,38 +17,29 @@ import io.minio.MinioClient; import io.minio.SetBucketTagsArgs; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; public class SetBucketTags { /** MinioClient.setBucketTags() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - minioClient.setBucketTags( - SetBucketTagsArgs.builder().bucket("my-bucketname").tags(map).build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + minioClient.setBucketTags(SetBucketTagsArgs.builder().bucket("my-bucket").tags(map).build()); } } diff --git a/examples/SetBucketVersioning.java b/examples/SetBucketVersioning.java index 94298543b..ad3e61850 100644 --- a/examples/SetBucketVersioning.java +++ b/examples/SetBucketVersioning.java @@ -18,46 +18,38 @@ import io.minio.SetBucketVersioningArgs; import io.minio.errors.MinioException; import io.minio.messages.VersioningConfiguration; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class SetBucketVersioning { /** MinioClient.setBucketVersioning() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Enable versioning on 'my-bucketname'. - minioClient.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket("my-bucketname") - .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) - .build()); - System.out.println("Bucket versioning is enabled successfully"); + // Enable versioning on 'my-bucket'. + minioClient.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket("my-bucket") + .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) + .build()); + System.out.println("Bucket versioning is enabled successfully"); - // Suspend versioning on 'my-bucketname'. - minioClient.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket("my-bucketname") - .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)) - .build()); - System.out.println("Bucket versioning is suspended successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Suspend versioning on 'my-bucket'. + minioClient.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket("my-bucket") + .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)) + .build()); + System.out.println("Bucket versioning is suspended successfully"); } } diff --git a/examples/SetObjectLockConfiguration.java b/examples/SetObjectLockConfiguration.java index 716518c9f..c2ac3f10a 100644 --- a/examples/SetObjectLockConfiguration.java +++ b/examples/SetObjectLockConfiguration.java @@ -18,44 +18,36 @@ import io.minio.SetObjectLockConfigurationArgs; import io.minio.errors.MinioException; import io.minio.messages.ObjectLockConfiguration; -import io.minio.messages.RetentionDurationDays; import io.minio.messages.RetentionMode; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; public class SetObjectLockConfiguration { /** MinioClient.setObjectLockConfiguration() exanple. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Declaring config with Retention mode as Compliance and duration as 100 days - ObjectLockConfiguration config = - new ObjectLockConfiguration(RetentionMode.COMPLIANCE, new RetentionDurationDays(100)); + // Declaring config with Retention mode as Compliance and duration as 100 days + ObjectLockConfiguration config = + new ObjectLockConfiguration( + RetentionMode.COMPLIANCE, new ObjectLockConfiguration.RetentionDurationDays(100)); - minioClient.setObjectLockConfiguration( - SetObjectLockConfigurationArgs.builder() - .bucket("my-lock-enabled-bucketname") - .config(config) - .build()); + minioClient.setObjectLockConfiguration( + SetObjectLockConfigurationArgs.builder() + .bucket("my-lock-enabled-bucketname") + .config(config) + .build()); - System.out.println("object-lock configuration is set successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + System.out.println("object-lock configuration is set successfully"); } } diff --git a/examples/SetObjectRetention.java b/examples/SetObjectRetention.java index 11303899e..7588e8abd 100644 --- a/examples/SetObjectRetention.java +++ b/examples/SetObjectRetention.java @@ -20,46 +20,37 @@ import io.minio.errors.MinioException; import io.minio.messages.Retention; import io.minio.messages.RetentionMode; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; public class SetObjectRetention { /** MinioClient.setObjectRetention() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException, IllegalArgumentException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Declaring config with Retention mode as Compliance and - // retain until 3 days from current date. - ZonedDateTime retentionUntil = ZonedDateTime.now(Time.UTC).plusDays(3).withNano(0); - Retention config = new Retention(RetentionMode.COMPLIANCE, retentionUntil); + // Declaring config with Retention mode as Compliance and + // retain until 3 days from current date. + ZonedDateTime retentionUntil = ZonedDateTime.now(Time.UTC).plusDays(3).withNano(0); + Retention config = new Retention(RetentionMode.COMPLIANCE, retentionUntil); - // Set object retention - minioClient.setObjectRetention( - SetObjectRetentionArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .config(config) - .bypassGovernanceMode(true) - .build()); - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Set object retention + minioClient.setObjectRetention( + SetObjectRetentionArgs.builder() + .bucket("my-bucket") + .object("my-object") + .config(config) + .bypassGovernanceMode(true) + .build()); } } diff --git a/examples/SetObjectTags.java b/examples/SetObjectTags.java index 5075e0229..6fa185800 100644 --- a/examples/SetObjectTags.java +++ b/examples/SetObjectTags.java @@ -17,42 +17,30 @@ import io.minio.MinioClient; import io.minio.SetObjectTagsArgs; import io.minio.errors.MinioException; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; public class SetObjectTags { /** MinioClient.setObjectTags() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - minioClient.setObjectTags( - SetObjectTagsArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .tags(map) - .build()); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + minioClient.setObjectTags( + SetObjectTagsArgs.builder().bucket("my-bucket").object("my-object").tags(map).build()); } } diff --git a/examples/StatObject.java b/examples/StatObject.java index f6a3e13d1..16f7004c9 100644 --- a/examples/StatObject.java +++ b/examples/StatObject.java @@ -15,11 +15,10 @@ */ import io.minio.MinioClient; -import io.minio.ServerSideEncryptionCustomerKey; +import io.minio.ServerSideEncryption; import io.minio.StatObjectArgs; import io.minio.StatObjectResponse; import io.minio.errors.MinioException; -import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.HashMap; @@ -28,92 +27,87 @@ public class StatObject { /** MinioClient.statObject() example. */ public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + throws InvalidKeyException, MinioException, NoSuchAlgorithmException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); - String versionId = "ac38316c-fe14-4f96-9f76-8f675ae5a79e"; + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); + String versionId = "ac38316c-fe14-4f96-9f76-8f675ae5a79e"; - { - // Get information of an object. - StatObjectResponse stat = - minioClient.statObject( - StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); - System.out.println(stat); - } - - { - // Get information of SSE-C encrypted object. - StatObjectResponse stat = - minioClient.statObject( - StatObjectArgs.builder() - .bucket("my-bucketname") - .object("my-encrypted-objectname") - .ssec(ssec) // Replace with actual key. - .build()); - System.out.println(stat); - } + { + // Get information of an object. + StatObjectResponse stat = + minioClient.statObject( + StatObjectArgs.builder().bucket("my-bucket").object("my-object").build()); + System.out.println(stat); + } - { - // Get information of a versioned object. - StatObjectResponse stat = - minioClient.statObject( - StatObjectArgs.builder() - .bucket("my-bucketname") - .object("my-versioned-objectname") - .versionId(versionId) // Replace with actual version ID. - .build()); - System.out.println(stat); - } + { + // Get information of SSE-C encrypted object. + StatObjectResponse stat = + minioClient.statObject( + StatObjectArgs.builder() + .bucket("my-bucket") + .object("my-encrypted-objectname") + .ssec(ssec) // Replace with actual key. + .build()); + System.out.println(stat); + } - { - // Get information of a SSE-C encrypted versioned object. - StatObjectResponse stat = - minioClient.statObject( - StatObjectArgs.builder() - .bucket("my-bucketname") - .object("my-encrypted-versioned-objectname") - .versionId(versionId) // Replace with actual version ID. - .ssec(ssec) // Replace with actual key. - .build()); - System.out.println(stat); - } + { + // Get information of a versioned object. + StatObjectResponse stat = + minioClient.statObject( + StatObjectArgs.builder() + .bucket("my-bucket") + .object("my-versioned-objectname") + .versionId(versionId) // Replace with actual version ID. + .build()); + System.out.println(stat); + } - { - // Get information of an object with extra headers and query parameters. - HashMap headers = new HashMap<>(); - headers.put("x-amz-request-payer", "requester"); - HashMap queryParams = new HashMap<>(); - queryParams.put("partNumber", "1"); + { + // Get information of a SSE-C encrypted versioned object. + StatObjectResponse stat = + minioClient.statObject( + StatObjectArgs.builder() + .bucket("my-bucket") + .object("my-encrypted-versioned-objectname") + .versionId(versionId) // Replace with actual version ID. + .ssec(ssec) // Replace with actual key. + .build()); + System.out.println(stat); + } - StatObjectResponse stat = - minioClient.statObject( - StatObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .extraHeaders(headers) // Replace with actual headers. - .extraQueryParams(queryParams) // Replace with actual query parameters. - .build()); - System.out.println(stat); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); + { + // Get information of an object with extra headers and query parameters. + HashMap headers = new HashMap<>(); + headers.put("x-amz-request-payer", "requester"); + HashMap queryParams = new HashMap<>(); + queryParams.put("partNumber", "1"); + StatObjectResponse stat = + minioClient.statObject( + StatObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .extraHeaders(headers) // Replace with actual headers. + .extraQueryParams(queryParams) // Replace with actual query parameters. + .build()); + System.out.println(stat); } } } diff --git a/examples/UploadObject.java b/examples/UploadObject.java index 35abedc48..f03792f1f 100644 --- a/examples/UploadObject.java +++ b/examples/UploadObject.java @@ -15,62 +15,52 @@ */ import io.minio.MinioClient; -import io.minio.ServerSideEncryptionCustomerKey; +import io.minio.ServerSideEncryption; import io.minio.UploadObjectArgs; import io.minio.errors.MinioException; -import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.KeyGenerator; public class UploadObject { - /** MinioClient.putObject() example. */ + /** MinioClient.uploadObject() example. */ public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + throws InvalidKeyException, MinioException, NoSuchAlgorithmException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - { - // Upload 'my-filename' as object 'my-objectname' in 'my-bucketname'. - minioClient.uploadObject( - UploadObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .filename("my-filename") - .build()); - System.out.println("my-filename is uploaded to my-objectname successfully"); - } + // Upload 'my-filename' as object 'my-object' in 'my-bucket'. + minioClient.uploadObject( + UploadObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .filename("my-filename") + .build()); + System.out.println("my-filename is uploaded to my-object successfully"); - { - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); - - // Upload 'my-filename' as object encrypted 'my-objectname' in 'my-bucketname'. - minioClient.uploadObject( - UploadObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .filename("my-filename") - .sse(ssec) - .build()); - System.out.println("my-filename is uploaded to my-objectname successfully"); - } - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Upload 'my-filename' as object encrypted 'my-object' in 'my-bucket'. + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); + minioClient.uploadObject( + UploadObjectArgs.builder() + .bucket("my-bucket") + .object("my-object") + .filename("my-filename") + .sse(ssec) + .build()); + System.out.println("my-filename is uploaded to my-object successfully"); } } diff --git a/examples/UploadSnowballObjects.java b/examples/UploadSnowballObjects.java index b292f2b3e..5de2ba925 100644 --- a/examples/UploadSnowballObjects.java +++ b/examples/UploadSnowballObjects.java @@ -19,51 +19,43 @@ import io.minio.UploadSnowballObjectsArgs; import io.minio.errors.MinioException; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; public class UploadSnowballObjects { /** MinioClient.uploadSnowballObjects() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - MinioClient.builder() - .endpoint("https://play.min.io") - .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") - .build(); + public static void main(String[] args) throws MinioException { + /* play.min.io for test and development. */ + MinioClient minioClient = + MinioClient.builder() + .endpoint("https://play.min.io") + .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG") + .build(); - /* Amazon S3: */ - // MinioClient minioClient = - // MinioClient.builder() - // .endpoint("https://s3.amazonaws.com") - // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") - // .build(); + /* Amazon S3: */ + // MinioClient minioClient = + // MinioClient.builder() + // .endpoint("https://s3.amazonaws.com") + // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") + // .build(); - // Upload snowball objects. - List objects = new ArrayList(); - objects.add( - new SnowballObject( - "my-object-one", - new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)), - 5, - null)); - objects.add( - new SnowballObject( - "my-object-two", - new ByteArrayInputStream("java".getBytes(StandardCharsets.UTF_8)), - 4, - null)); - minioClient.uploadSnowballObjects( - UploadSnowballObjectsArgs.builder().bucket("my-bucketname").objects(objects).build()); - System.out.println("my-object-one and my-object-two are successfully uploaded"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } + // Upload snowball objects. + List objects = new ArrayList(); + objects.add( + new SnowballObject( + "my-object-one", + new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)), + 5, + null)); + objects.add( + new SnowballObject( + "my-object-two", + new ByteArrayInputStream("java".getBytes(StandardCharsets.UTF_8)), + 4, + null)); + minioClient.uploadSnowballObjects( + UploadSnowballObjectsArgs.builder().bucket("my-bucket").objects(objects).build()); + System.out.println("my-object-one and my-object-two are successfully uploaded"); } } diff --git a/functional/FunctionalTest.java b/functional/FunctionalTest.java index 3f2234333..d87e38d69 100644 --- a/functional/FunctionalTest.java +++ b/functional/FunctionalTest.java @@ -1,4247 +1,117 @@ -/* - * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, - * (C) 2015-2021 MinIO, 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. - */ - -import static java.nio.file.StandardOpenOption.APPEND; -import static java.nio.file.StandardOpenOption.CREATE; - -import com.google.common.io.BaseEncoding; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.minio.BucketExistsArgs; -import io.minio.CloseableIterator; -import io.minio.ComposeObjectArgs; -import io.minio.ComposeSource; -import io.minio.CopyObjectArgs; -import io.minio.CopySource; -import io.minio.DeleteBucketCorsArgs; -import io.minio.DeleteBucketEncryptionArgs; -import io.minio.DeleteBucketLifecycleArgs; -import io.minio.DeleteBucketNotificationArgs; -import io.minio.DeleteBucketPolicyArgs; -import io.minio.DeleteBucketReplicationArgs; -import io.minio.DeleteBucketTagsArgs; -import io.minio.DeleteObjectLockConfigurationArgs; -import io.minio.DeleteObjectTagsArgs; -import io.minio.Directive; -import io.minio.DisableObjectLegalHoldArgs; -import io.minio.DownloadObjectArgs; -import io.minio.EnableObjectLegalHoldArgs; -import io.minio.GetBucketCorsArgs; -import io.minio.GetBucketEncryptionArgs; -import io.minio.GetBucketLifecycleArgs; -import io.minio.GetBucketNotificationArgs; -import io.minio.GetBucketPolicyArgs; -import io.minio.GetBucketReplicationArgs; -import io.minio.GetBucketTagsArgs; -import io.minio.GetBucketVersioningArgs; -import io.minio.GetObjectAclArgs; -import io.minio.GetObjectArgs; -import io.minio.GetObjectAttributesArgs; -import io.minio.GetObjectAttributesResponse; -import io.minio.GetObjectLockConfigurationArgs; -import io.minio.GetObjectRetentionArgs; -import io.minio.GetObjectTagsArgs; -import io.minio.GetPresignedObjectUrlArgs; -import io.minio.IsObjectLegalHoldEnabledArgs; -import io.minio.ListBucketsArgs; -import io.minio.ListObjectsArgs; -import io.minio.ListenBucketNotificationArgs; -import io.minio.MakeBucketArgs; -import io.minio.MinioClient; -import io.minio.ObjectWriteResponse; -import io.minio.PostPolicy; -import io.minio.PutObjectArgs; -import io.minio.PutObjectFanOutArgs; -import io.minio.PutObjectFanOutEntry; -import io.minio.RemoveBucketArgs; -import io.minio.RemoveObjectArgs; -import io.minio.RemoveObjectsArgs; -import io.minio.Result; -import io.minio.SelectObjectContentArgs; -import io.minio.SelectResponseStream; -import io.minio.ServerSideEncryption; -import io.minio.ServerSideEncryptionCustomerKey; -import io.minio.ServerSideEncryptionKms; -import io.minio.ServerSideEncryptionS3; -import io.minio.SetBucketCorsArgs; -import io.minio.SetBucketEncryptionArgs; -import io.minio.SetBucketLifecycleArgs; -import io.minio.SetBucketNotificationArgs; -import io.minio.SetBucketPolicyArgs; -import io.minio.SetBucketReplicationArgs; -import io.minio.SetBucketTagsArgs; -import io.minio.SetBucketVersioningArgs; -import io.minio.SetObjectLockConfigurationArgs; -import io.minio.SetObjectRetentionArgs; -import io.minio.SetObjectTagsArgs; -import io.minio.SnowballObject; -import io.minio.StatObjectArgs; -import io.minio.StatObjectResponse; -import io.minio.Time; -import io.minio.UploadObjectArgs; -import io.minio.UploadSnowballObjectsArgs; -import io.minio.Xml; -import io.minio.admin.MinioAdminClient; -import io.minio.errors.ErrorResponseException; -import io.minio.http.HttpUtils; -import io.minio.http.Method; -import io.minio.messages.AccessControlPolicy; -import io.minio.messages.AndOperator; -import io.minio.messages.Bucket; -import io.minio.messages.CORSConfiguration; -import io.minio.messages.DeleteMarkerReplication; -import io.minio.messages.DeleteObject; -import io.minio.messages.Event; -import io.minio.messages.EventType; -import io.minio.messages.Expiration; -import io.minio.messages.FileHeaderInfo; -import io.minio.messages.GranteeType; -import io.minio.messages.InputSerialization; -import io.minio.messages.LifecycleConfiguration; -import io.minio.messages.LifecycleRule; -import io.minio.messages.NotificationConfiguration; -import io.minio.messages.NotificationRecords; -import io.minio.messages.ObjectLockConfiguration; -import io.minio.messages.OutputSerialization; -import io.minio.messages.Permission; -import io.minio.messages.QueueConfiguration; -import io.minio.messages.QuoteFields; -import io.minio.messages.ReplicationConfiguration; -import io.minio.messages.ReplicationDestination; -import io.minio.messages.ReplicationRule; -import io.minio.messages.Retention; -import io.minio.messages.RetentionDuration; -import io.minio.messages.RetentionDurationDays; -import io.minio.messages.RetentionDurationYears; -import io.minio.messages.RetentionMode; -import io.minio.messages.RuleFilter; -import io.minio.messages.SseAlgorithm; -import io.minio.messages.SseConfiguration; -import io.minio.messages.Stats; -import io.minio.messages.Status; -import io.minio.messages.Tags; -import io.minio.messages.VersioningConfiguration; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.InvalidKeyException; -import java.security.KeyManagementException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import javax.crypto.KeyGenerator; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MultipartBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okio.BufferedSink; -import okio.Okio; -import org.junit.Assert; - -@SuppressFBWarnings( - value = "REC", - justification = "Allow catching super class Exception since it's tests") -public class FunctionalTest { - private static final String OS = System.getProperty("os.name").toLowerCase(Locale.US); - private static final String MINIO_BINARY; - private static final String PASS = "PASS"; - private static final String FAILED = "FAIL"; - private static final String IGNORED = "NA"; - private static final int KB = 1024; - private static final int MB = 1024 * 1024; - private static final Random random = new Random(new SecureRandom().nextLong()); - private static final String customContentType = "application/javascript"; - private static String bucketName = getRandomName(); - private static String bucketNameWithLock = getRandomName(); - private static boolean mintEnv = false; - private static boolean isQuickTest = false; - private static boolean isRunOnFail = false; - private static Path dataFile1Kb; - private static Path dataFile6Mb; - private static String endpoint; - private static String endpointTLS; - private static String accessKey; - private static String secretKey; - private static String region; - private static boolean isSecureEndpoint = false; - private static String sqsArn = null; - private static String replicationSrcBucket = null; - private static String replicationRole = null; - private static String replicationBucketArn = null; - private static MinioClient client = null; - private static TestMinioAdminClient adminClientTests; - - private static ServerSideEncryptionCustomerKey ssec = null; - private static ServerSideEncryption sseS3 = new ServerSideEncryptionS3(); - private static ServerSideEncryption sseKms = null; - - static { - String binaryName = "minio"; - if (OS.contains("windows")) { - binaryName = "minio.exe"; - } - - MINIO_BINARY = binaryName; - - try { - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - ssec = new ServerSideEncryptionCustomerKey(keyGen.generateKey()); - } catch (InvalidKeyException | NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - public static OkHttpClient newHttpClient() { - try { - return HttpUtils.disableCertCheck( - HttpUtils.newDefaultHttpClient( - TimeUnit.MINUTES.toMillis(5), - TimeUnit.MINUTES.toMillis(5), - TimeUnit.MINUTES.toMillis(5))); - } catch (KeyManagementException | NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - /** Do no-op. */ - public static void ignore(Object... args) {} - - /** Create given sized file and returns its name. */ - public static String createFile(int size) throws IOException { - String filename = getRandomName(); - - try (OutputStream os = Files.newOutputStream(Paths.get(filename), CREATE, APPEND)) { - int totalBytesWritten = 0; - int bytesToWrite = 0; - byte[] buf = new byte[1 * MB]; - while (totalBytesWritten < size) { - random.nextBytes(buf); - bytesToWrite = size - totalBytesWritten; - if (bytesToWrite > buf.length) { - bytesToWrite = buf.length; - } - - os.write(buf, 0, bytesToWrite); - totalBytesWritten += bytesToWrite; - } - } - - return filename; - } - - /** Create 1 KB temporary file. */ - public static String createFile1Kb() throws IOException { - if (mintEnv) { - String filename = getRandomName(); - Files.createSymbolicLink(Paths.get(filename).toAbsolutePath(), dataFile1Kb); - return filename; - } - - return createFile(1 * KB); - } - - /** Create 6 MB temporary file. */ - public static String createFile6Mb() throws IOException { - if (mintEnv) { - String filename = getRandomName(); - Files.createSymbolicLink(Paths.get(filename).toAbsolutePath(), dataFile6Mb); - return filename; - } - - return createFile(6 * MB); - } - - /** Generate random name. */ - public static String getRandomName() { - return "minio-java-test-" + new BigInteger(32, random).toString(32); - } - - /** Returns byte array contains all data in given InputStream. */ - public static byte[] readAllBytes(InputStream is) throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nRead; - byte[] data = new byte[16384]; - while ((nRead = is.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - return buffer.toByteArray(); - } - - /** Prints a success log entry in JSON format. */ - public static void mintSuccessLog(String function, String args, long startTime) { - if (mintEnv) { - System.out.println( - new MintLogger( - function, args, System.currentTimeMillis() - startTime, PASS, null, null, null)); - } - } - - /** Prints a failure log entry in JSON format. */ - public static void mintFailedLog( - String function, String args, long startTime, String message, String error) { - if (mintEnv) { - System.out.println( - new MintLogger( - function, - args, - System.currentTimeMillis() - startTime, - FAILED, - null, - message, - error)); - } - } - - /** Prints a ignore log entry in JSON format. */ - public static void mintIgnoredLog(String function, String args, long startTime) { - if (mintEnv) { - System.out.println( - new MintLogger( - function, args, System.currentTimeMillis() - startTime, IGNORED, null, null, null)); - } - } - - /** Read object content of the given url. */ - public static byte[] readObject(String urlString) throws Exception { - Request.Builder requestBuilder = new Request.Builder(); - Request request = requestBuilder.url(HttpUrl.parse(urlString)).method("GET", null).build(); - OkHttpClient transport = newHttpClient(); - Response response = transport.newCall(request).execute(); - - try { - if (response.isSuccessful()) { - return response.body().bytes(); - } - - String errorXml = response.body().string(); - throw new Exception( - "failed to create object. Response: " + response + ", Response body: " + errorXml); - } finally { - response.close(); - } - } - - /** Write data to given object url. */ - public static void writeObject(String urlString, byte[] dataBytes) throws Exception { - Request.Builder requestBuilder = new Request.Builder(); - // Set header 'x-amz-acl' to 'bucket-owner-full-control', so objects created - // anonymously, can be downloaded by bucket owner in AWS S3. - Request request = - requestBuilder - .url(HttpUrl.parse(urlString)) - .method("PUT", RequestBody.create(dataBytes, null)) - .addHeader("x-amz-acl", "bucket-owner-full-control") - .build(); - OkHttpClient transport = newHttpClient(); - Response response = transport.newCall(request).execute(); - - try { - if (!response.isSuccessful()) { - String errorXml = response.body().string(); - throw new Exception( - "failed to create object. Response: " + response + ", Response body: " + errorXml); - } - } finally { - response.close(); - } - } - - public static String getSha256Sum(InputStream stream, int len) throws Exception { - MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256"); - - // 16KiB buffer for optimization - byte[] buf = new byte[16384]; - int bytesToRead = buf.length; - int bytesRead = 0; - int totalBytesRead = 0; - while (totalBytesRead < len) { - if ((len - totalBytesRead) < bytesToRead) { - bytesToRead = len - totalBytesRead; - } - - bytesRead = stream.read(buf, 0, bytesToRead); - Assert.assertFalse( - "data length mismatch. expected: " + len + ", got: " + totalBytesRead, bytesRead < 0); - - if (bytesRead > 0) { - sha256Digest.update(buf, 0, bytesRead); - totalBytesRead += bytesRead; - } - } - - return BaseEncoding.base16().encode(sha256Digest.digest()).toLowerCase(Locale.US); - } - - public static void skipStream(InputStream stream, int len) throws Exception { - // 16KiB buffer for optimization - byte[] buf = new byte[16384]; - int bytesToRead = buf.length; - int bytesRead = 0; - int totalBytesRead = 0; - while (totalBytesRead < len) { - if ((len - totalBytesRead) < bytesToRead) { - bytesToRead = len - totalBytesRead; - } - - bytesRead = stream.read(buf, 0, bytesToRead); - Assert.assertFalse( - "insufficient data. expected: " + len + ", got: " + totalBytesRead, bytesRead < 0); - if (bytesRead > 0) { - totalBytesRead += bytesRead; - } - } - } - - public static void handleException(String methodName, String args, long startTime, Exception e) - throws Exception { - if (e instanceof ErrorResponseException) { - if (((ErrorResponseException) e).errorResponse().code().equals("NotImplemented")) { - mintIgnoredLog(methodName, args, startTime); - return; - } - } - - if (mintEnv) { - mintFailedLog( - methodName, - args, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - if (isRunOnFail) { - return; - } - } else { - System.out.println(" " + methodName + " " + ((args == null) ? "" : args)); - } - - throw e; - } - - public static void testBucketApi( - String methodName, - String testTags, - MakeBucketArgs args, - boolean existCheck, - boolean removeCheck) - throws Exception { - long startTime = System.currentTimeMillis(); - try { - client.makeBucket(args); - try { - Assert.assertFalse( - methodName + " failed after bucket creation", - existCheck - && !client.bucketExists( - BucketExistsArgs.builder() - .bucket(args.bucket()) - .region(args.region()) - .build())); - if (removeCheck) { - client.removeBucket( - RemoveBucketArgs.builder().bucket(args.bucket()).region(args.region()).build()); - } - mintSuccessLog(methodName, null, startTime); - } finally { - if (!removeCheck) { - client.removeBucket( - RemoveBucketArgs.builder().bucket(args.bucket()).region(args.region()).build()); - } - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testBucketApiCases(String methodName, boolean existCheck, boolean removeCheck) - throws Exception { - testBucketApi( - methodName, - "[basic check]", - MakeBucketArgs.builder().bucket(getRandomName()).build(), - existCheck, - removeCheck); - - if (isQuickTest) { - return; - } - - testBucketApi( - methodName, - "[object lock]", - MakeBucketArgs.builder().bucket(getRandomName()).objectLock(true).build(), - existCheck, - removeCheck); - testBucketApi( - methodName, - "[name contains period]", - MakeBucketArgs.builder().bucket(getRandomName() + ".withperiod").build(), - existCheck, - removeCheck); - } - - public static void makeBucket() throws Exception { - String methodName = "makeBucket()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testBucketApiCases(methodName, false, false); - - if (isQuickTest) { - return; - } - - if (!endpoint.contains(".amazonaws.com")) { - mintIgnoredLog(methodName, "[region]", System.currentTimeMillis()); - mintIgnoredLog(methodName, "[region, object lock]", System.currentTimeMillis()); - return; - } - - testBucketApi( - methodName, - "[region]", - MakeBucketArgs.builder().bucket(getRandomName()).region("eu-west-1").build(), - false, - false); - testBucketApi( - methodName, - "[region, object lock]", - MakeBucketArgs.builder() - .bucket(getRandomName()) - .region("eu-central-1") - .objectLock(true) - .build(), - false, - false); - } - - public static void listBuckets() throws Exception { - String methodName = "listBuckets()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - List expectedBucketNames = new LinkedList<>(); - try { - try { - String bucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - expectedBucketNames.add(bucketName); - - bucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); - expectedBucketNames.add(bucketName); - - bucketName = getRandomName() + ".withperiod"; - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - expectedBucketNames.add(bucketName); - - List bucketNames = new LinkedList<>(); - for (Result result : - client.listBuckets(ListBucketsArgs.builder().maxBuckets(1).build())) { - Bucket bucket = result.get(); - if (expectedBucketNames.contains(bucket.name())) { - bucketNames.add(bucket.name()); - } - } - - Assert.assertTrue( - "bucket names differ; expected = " + expectedBucketNames + ", got = " + bucketNames, - expectedBucketNames.containsAll(bucketNames)); - - mintSuccessLog(methodName, null, startTime); - } finally { - for (String bucketName : expectedBucketNames) { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void bucketExists() throws Exception { - String methodName = "bucketExists()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testBucketApiCases(methodName, true, false); - } - - public static void removeBucket() throws Exception { - String methodName = "removeBucket()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testBucketApiCases(methodName, false, true); - } - - public static void setBucketVersioning() throws Exception { - String methodName = "setBucketVersioning()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String name = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(name).build()); - try { - client.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket(name) - .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) - .build()); - client.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket(name) - .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)) - .build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(name).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketVersioning() throws Exception { - String methodName = "getBucketVersioning()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String name = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(name).build()); - try { - VersioningConfiguration config = - client.getBucketVersioning(GetBucketVersioningArgs.builder().bucket(name).build()); - Assert.assertEquals( - "getBucketVersioning(); expected = \"\", got = " + config.status(), - config.status(), - VersioningConfiguration.Status.OFF); - client.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket(name) - .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) - .build()); - config = client.getBucketVersioning(GetBucketVersioningArgs.builder().bucket(name).build()); - Assert.assertEquals( - "getBucketVersioning(); expected = " - + VersioningConfiguration.Status.ENABLED - + ", got = " - + config.status(), - config.status(), - VersioningConfiguration.Status.ENABLED); - - client.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket(name) - .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)) - .build()); - config = client.getBucketVersioning(GetBucketVersioningArgs.builder().bucket(name).build()); - Assert.assertEquals( - "getBucketVersioning(); expected = " - + VersioningConfiguration.Status.SUSPENDED - + ", got = " - + config.status(), - config.status(), - VersioningConfiguration.Status.SUSPENDED); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(name).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setup() throws Exception { - long startTime = System.currentTimeMillis(); - - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - } catch (Exception e) { - handleException("makeBucket()", null, startTime, e); - } - - try { - client.makeBucket( - MakeBucketArgs.builder().bucket(bucketNameWithLock).objectLock(true).build()); - } catch (Exception e) { - if (e instanceof ErrorResponseException) { - if (((ErrorResponseException) e).errorResponse().code().equals("NotImplemented")) { - bucketNameWithLock = null; - return; - } - } - - handleException("makeBucket()", "[object lock]", startTime, e); - } - } - - public static void teardown() throws Exception { - long startTime = System.currentTimeMillis(); - try { - if (bucketName != null) { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - - if (bucketNameWithLock != null) { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketNameWithLock).build()); - } - } catch (Exception e) { - handleException("removeBucket()", null, startTime, e); - } - } - - public static void testUploadObject(String testTags, String filename, String contentType) - throws Exception { - String methodName = "uploadObject()"; - long startTime = System.currentTimeMillis(); - try { - try { - UploadObjectArgs.Builder builder = - UploadObjectArgs.builder().bucket(bucketName).object(filename).filename(filename); - if (contentType != null) { - builder.contentType(contentType); - } - client.uploadObject(builder.build()); - mintSuccessLog(methodName, testTags, startTime); - } finally { - Files.delete(Paths.get(filename)); - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(filename).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void uploadObject() throws Exception { - String methodName = "uploadObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testUploadObject("[single upload]", createFile1Kb(), null); - - if (isQuickTest) { - return; - } - - testUploadObject("[multi-part upload]", createFile6Mb(), null); - testUploadObject("[custom content-type]", createFile1Kb(), customContentType); - } - - public static void testPutObject(String testTags, PutObjectArgs args, String errorCode) - throws Exception { - String methodName = "putObject()"; - long startTime = System.currentTimeMillis(); - try { - ObjectWriteResponse objectInfo = null; - try { - objectInfo = client.putObject(args); - } catch (ErrorResponseException e) { - if (errorCode == null || !e.errorResponse().code().equals(errorCode)) { - throw e; - } - } - if (args.retention() != null) { - client.setObjectRetention( - SetObjectRetentionArgs.builder() - .bucket(args.bucket()) - .object(args.object()) - .config(new Retention()) - .bypassGovernanceMode(true) - .build()); - } - client.removeObject( - RemoveObjectArgs.builder() - .bucket(args.bucket()) - .object(args.object()) - .versionId(objectInfo != null ? objectInfo.versionId() : null) - .build()); - - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testThreadedPutObject() throws Exception { - String methodName = "putObject()"; - String testTags = "[threaded]"; - long startTime = System.currentTimeMillis(); - try { - int count = 7; - Thread[] threads = new Thread[count]; - - for (int i = 0; i < count; i++) { - threads[i] = new Thread(new PutObjectRunnable(client, bucketName, createFile6Mb())); - } - - for (int i = 0; i < count; i++) { - threads[i].start(); - } - - // Waiting for threads to complete. - for (int i = 0; i < count; i++) { - threads[i].join(); - } - - // All threads are completed. - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void putObject() throws Exception { - String methodName = "putObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testPutObject( - "[single upload]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .contentType(customContentType) - .build(), - null); - - if (isQuickTest) { - return; - } - - testPutObject( - "[multi-part upload]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(11 * MB), 11 * MB, -1) - .contentType(customContentType) - .build(), - null); - - testPutObject( - "[object name with path segments]", - PutObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .contentType(customContentType) - .build(), - null); - - testPutObject( - "[zero sized object]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(0), 0, -1) - .build(), - null); - - testPutObject( - "[object name ends with '/']", - PutObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName() + "/") - .stream(new ContentInputStream(0), 0, -1) - .contentType(customContentType) - .build(), - null); - - testPutObject( - "[unknown stream size, single upload]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), -1, PutObjectArgs.MIN_MULTIPART_SIZE) - .contentType(customContentType) - .build(), - null); - - testPutObject( - "[unknown stream size, multi-part upload]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(11 * MB), -1, PutObjectArgs.MIN_MULTIPART_SIZE) - .contentType(customContentType) - .build(), - null); - - Map userMetadata = new HashMap<>(); - userMetadata.put("My-Project", "Project One"); - userMetadata.put("My-header1", " a b c "); - userMetadata.put("My-Header2", "\"a b c\""); - userMetadata.put("My-Unicode-Tag", "商品"); - - testPutObject( - "[user metadata]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .userMetadata(userMetadata) - .build(), - null); - - Map headers = new HashMap<>(); - - headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); - testPutObject( - "[storage-class=REDUCED_REDUNDANCY]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .headers(headers) - .build(), - null); - - headers.put("X-Amz-Storage-Class", "STANDARD"); - testPutObject( - "[storage-class=STANDARD]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .headers(headers) - .build(), - null); - - headers.put("X-Amz-Storage-Class", "INVALID"); - testPutObject( - "[storage-class=INVALID negative case]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .headers(headers) - .build(), - "InvalidStorageClass"); - - testPutObject( - "[SSE-S3]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .contentType(customContentType) - .sse(sseS3) - .build(), - null); - - if (bucketNameWithLock != null) { - testPutObject( - "[with retention]", - PutObjectArgs.builder().bucket(bucketNameWithLock).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .retention( - new Retention(RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(1))) - .build(), - null); - } - - testThreadedPutObject(); - - if (!isSecureEndpoint) { - return; - } - - testPutObject( - "[SSE-C single upload]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .contentType(customContentType) - .sse(ssec) - .build(), - null); - - testPutObject( - "[SSE-C multi-part upload]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(11 * MB), 11 * MB, -1) - .contentType(customContentType) - .sse(ssec) - .build(), - null); - - if (sseKms == null) { - mintIgnoredLog(methodName, null, System.currentTimeMillis()); - return; - } - - testPutObject( - "[SSE-KMS]", - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .contentType(customContentType) - .sse(sseKms) - .build(), - null); - } - - public static void testStatObject( - String testTags, PutObjectArgs args, StatObjectResponse expectedStat) throws Exception { - String methodName = "statObject()"; - long startTime = System.currentTimeMillis(); - try { - client.putObject(args); - try { - ServerSideEncryptionCustomerKey ssec = null; - if (args.sse() instanceof ServerSideEncryptionCustomerKey) { - ssec = (ServerSideEncryptionCustomerKey) args.sse(); - } - StatObjectResponse stat = - client.statObject( - StatObjectArgs.builder() - .bucket(args.bucket()) - .object(args.object()) - .ssec(ssec) - .build()); - - Assert.assertEquals( - "bucket name: expected = " + expectedStat.bucket() + ", got = " + stat.bucket(), - expectedStat.bucket(), - stat.bucket()); - - Assert.assertEquals( - "object name: expected = " + expectedStat.object() + ", got = " + stat.object(), - expectedStat.object(), - stat.object()); - - Assert.assertEquals( - "length: expected = " + expectedStat.size() + ", got = " + stat.size(), - expectedStat.size(), - stat.size()); - - Assert.assertEquals( - "content-type: expected = " - + expectedStat.contentType() - + ", got = " - + stat.contentType(), - expectedStat.contentType(), - stat.contentType()); - - for (String key : expectedStat.userMetadata().keySet()) { - Assert.assertTrue("metadata " + key + " not found", stat.userMetadata().containsKey(key)); - Assert.assertEquals( - "metadata " - + key - + " value: expected: " - + expectedStat.userMetadata().get(key) - + ", got: " - + stat.userMetadata().get(key), - expectedStat.userMetadata().get(key), - stat.userMetadata().get(key)); - } - - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void statObject() throws Exception { - String methodName = "statObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - String objectName = getRandomName(); - - PutObjectArgs.Builder builder = - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1024), 1024, -1); - Headers.Builder headersBuilder = - new Headers.Builder() - .add("Content-Type: application/octet-stream") - .add("Content-Length: 1024") - .add("Last-Modified", ZonedDateTime.now().format(Time.HTTP_HEADER_DATE_FORMAT)); - - testStatObject( - "[basic check]", - builder.build(), - new StatObjectResponse(headersBuilder.build(), bucketName, null, objectName)); - - Map headers = new HashMap<>(); - headers.put("Content-Type", customContentType); - Map userMetadata = new HashMap<>(); - userMetadata.put("My-Project", "Project One"); - builder = builder.headers(headers).userMetadata(userMetadata); - builder = builder.stream(new ContentInputStream(1024), 1024, -1); - - StatObjectResponse stat = - new StatObjectResponse( - headersBuilder - .set("Content-Type", customContentType) - .add("X-Amz-Meta-My-Project: Project One") - .build(), - bucketName, - null, - objectName); - - testStatObject("[user metadata]", builder.build(), stat); - - if (isQuickTest) { - return; - } - - builder = builder.stream(new ContentInputStream(1024), 1024, -1); - testStatObject("[SSE-S3]", builder.sse(sseS3).build(), stat); - - if (!isSecureEndpoint) { - mintIgnoredLog(methodName, "[SSE-C]", System.currentTimeMillis()); - return; - } - - builder = builder.stream(new ContentInputStream(1024), 1024, -1); - testStatObject("[SSE-C]", builder.sse(ssec).build(), stat); - - if (sseKms == null) { - mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); - return; - } - - builder = builder.stream(new ContentInputStream(1024), 1024, -1); - testStatObject("[SSE-KMS]", builder.sse(sseKms).build(), stat); - } - - public static void testGetObject( - String testTags, - long objectSize, - ServerSideEncryption sse, - GetObjectArgs args, - int length, - String sha256sum) - throws Exception { - String methodName = "getObject()"; - long startTime = System.currentTimeMillis(); - try { - PutObjectArgs.Builder builder = - PutObjectArgs.builder().bucket(args.bucket()).object(args.object()).stream( - new ContentInputStream(objectSize), objectSize, -1); - if (sse != null) { - builder.sse(sse); - } - client.putObject(builder.build()); - - try (InputStream is = client.getObject(args)) { - String checksum = getSha256Sum(is, length); - Assert.assertEquals( - "checksum mismatch. expected: " + sha256sum + ", got: " + checksum, - checksum, - sha256sum); - } - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - } - } - - public static void getObject() throws Exception { - String methodName = "getObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testGetObject( - "[single upload]", - 1 * KB, - null, - GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).build(), - 1 * KB, - getSha256Sum(new ContentInputStream(1 * KB), 1 * KB)); - - if (isQuickTest) { - return; - } - - InputStream cis = new ContentInputStream(1 * KB); - skipStream(cis, 1000); - testGetObject( - "[single upload, offset]", - 1 * KB, - null, - GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).offset(1000L).build(), - 1 * KB - 1000, - getSha256Sum(cis, 1 * KB - 1000)); - - testGetObject( - "[single upload, length]", - 1 * KB, - null, - GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).length(256L).build(), - 256, - getSha256Sum(new ContentInputStream(1 * KB), 256)); - - cis = new ContentInputStream(1 * KB); - skipStream(cis, 1000); - testGetObject( - "[single upload, offset, length]", - 1 * KB, - null, - GetObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .offset(1000L) - .length(24L) - .build(), - 24, - getSha256Sum(cis, 24)); - - cis = new ContentInputStream(1 * KB); - skipStream(cis, 1000); - testGetObject( - "[single upload, offset, length beyond available]", - 1 * KB, - null, - GetObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .offset(1000L) - .length(30L) - .build(), - 24, - getSha256Sum(cis, 24)); - - testGetObject( - "[multi-part upload]", - 6 * MB, - null, - GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).build(), - 6 * MB, - getSha256Sum(new ContentInputStream(6 * MB), 6 * MB)); - - cis = new ContentInputStream(6 * MB); - skipStream(cis, 1000); - testGetObject( - "[multi-part upload, offset, length]", - 6 * MB, - null, - GetObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .offset(1000L) - .length(64 * 1024L) - .build(), - 64 * KB, - getSha256Sum(cis, 64 * 1024)); - - cis = new ContentInputStream(0); - testGetObject( - "[zero sized object]", - 0, - null, - GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).build(), - 0, - getSha256Sum(cis, 0)); - - if (!isSecureEndpoint) { - return; - } - - testGetObject( - "[single upload, SSE-C]", - 1 * KB, - ssec, - GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).ssec(ssec).build(), - 1 * KB, - getSha256Sum(new ContentInputStream(1 * KB), 1 * KB)); - } - - public static void testDownloadObject( - String testTags, int objectSize, ServerSideEncryption sse, DownloadObjectArgs args) - throws Exception { - String methodName = "downloadObject()"; - long startTime = System.currentTimeMillis(); - try { - PutObjectArgs.Builder builder = - PutObjectArgs.builder().bucket(args.bucket()).object(args.object()).stream( - new ContentInputStream(objectSize), objectSize, -1); - if (sse != null) { - builder.sse(sse); - } - client.putObject(builder.build()); - client.downloadObject(args); - Files.delete(Paths.get(args.filename())); - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - } - } - - public static void downloadObject() throws Exception { - String methodName = "downloadObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - String objectName = getRandomName(); - testDownloadObject( - "[single upload]", - 1 * KB, - null, - DownloadObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .filename(objectName + ".downloaded") - .build()); - - if (isQuickTest) { - return; - } - - String baseName = getRandomName(); - objectName = "path/to/" + baseName; - testDownloadObject( - "[single upload with multiple path segments]", - 1 * KB, - null, - DownloadObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .filename(baseName + ".downloaded") - .build()); - - if (!isSecureEndpoint) { - return; - } - - objectName = getRandomName(); - testDownloadObject( - "[single upload, SSE-C]", - 1 * KB, - ssec, - DownloadObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .ssec(ssec) - .filename(objectName + ".downloaded") - .build()); - } - - public static List createObjects(String bucketName, int count, int versions) - throws Exception { - List results = new LinkedList<>(); - for (int i = 0; i < count; i++) { - String objectName = getRandomName(); - results.add( - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1), 1, -1) - .build())); - if (versions > 1) { - for (int j = 0; j < versions - 1; j++) { - results.add( - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1), 1, -1) - .build())); - } - } - } - - return results; - } - - public static void removeObjects(String bucketName, List results) - throws Exception { - List objects = - results.stream() - .map( - result -> { - return new DeleteObject(result.object(), result.versionId()); - }) - .collect(Collectors.toList()); - for (Result r : - client.removeObjects( - RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build())) { - ignore(r.get()); - } - } - - public static void testListObjects( - String testTags, ListObjectsArgs args, int objCount, int versions) throws Exception { - String methodName = "listObjects()"; - long startTime = System.currentTimeMillis(); - String bucketName = args.bucket(); - List results = null; - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - if (versions > 0) { - client.setBucketVersioning( - SetBucketVersioningArgs.builder() - .bucket(bucketName) - .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) - .build()); - } - - results = createObjects(bucketName, objCount, versions); - - int i = 0; - for (Result r : client.listObjects(args)) { - r.get(); - i++; - } - - if (versions > 0) { - objCount *= versions; - } - - Assert.assertEquals("object count; expected=" + objCount + ", got=" + i, i, objCount); - mintSuccessLog(methodName, testTags, startTime); - } finally { - if (results != null) { - removeObjects(bucketName, results); - } - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void listObjects() throws Exception { - if (!mintEnv) { - System.out.println("listObjects()"); - } - - testListObjects("[bucket]", ListObjectsArgs.builder().bucket(getRandomName()).build(), 3, 0); - - testListObjects( - "[bucket, prefix]", - ListObjectsArgs.builder().bucket(getRandomName()).prefix("minio").build(), - 3, - 0); - - testListObjects( - "[bucket, prefix, recursive]", - ListObjectsArgs.builder().bucket(getRandomName()).prefix("minio").recursive(true).build(), - 3, - 0); - - testListObjects( - "[bucket, versions]", - ListObjectsArgs.builder().bucket(getRandomName()).includeVersions(true).build(), - 3, - 2); - - if (isQuickTest) { - return; - } - - testListObjects( - "[empty bucket]", ListObjectsArgs.builder().bucket(getRandomName()).build(), 0, 0); - - testListObjects( - "[bucket, prefix, recursive, 1050 objects]", - ListObjectsArgs.builder().bucket(getRandomName()).prefix("minio").recursive(true).build(), - 1050, - 0); - - testListObjects( - "[bucket, apiVersion1]", - ListObjectsArgs.builder().bucket(getRandomName()).useApiVersion1(true).build(), - 3, - 0); - } - - public static void testRemoveObject( - String testTags, ServerSideEncryption sse, RemoveObjectArgs args) throws Exception { - String methodName = "removeObject()"; - long startTime = System.currentTimeMillis(); - try { - PutObjectArgs.Builder builder = - PutObjectArgs.builder().bucket(args.bucket()).object(args.object()).stream( - new ContentInputStream(1), 1, -1); - if (sse != null) { - builder.sse(sse); - } - client.putObject(builder.build()); - client.removeObject(args); - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void removeObject() throws Exception { - String methodName = "removeObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testRemoveObject( - "[base check]", - null, - RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); - testRemoveObject( - "[multiple path segments]", - null, - RemoveObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName()).build()); - - if (isQuickTest) { - return; - } - - testRemoveObject( - "[SSE-S3]", - sseS3, - RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); - - if (!isSecureEndpoint) { - mintIgnoredLog(methodName, "[SSE-C]", System.currentTimeMillis()); - mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); - return; - } - - testRemoveObject( - "[SSE-C]", - ssec, - RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); - - if (sseKms == null) { - mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); - return; - } - - testRemoveObject( - "[SSE-KMS]", - sseKms, - RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); - } - - public static void testRemoveObjects(String testTags, List results) - throws Exception { - String methodName = "removeObjects()"; - long startTime = System.currentTimeMillis(); - try { - removeObjects(bucketName, results); - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } finally { - removeObjects(bucketName, results); - } - } - - public static void removeObjects() throws Exception { - String methodName = "removeObjects()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testRemoveObjects("[basic]", createObjects(bucketName, 3, 0)); - - String testTags = "[3005 objects]"; - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - List results = new LinkedList<>(); - for (int i = 0; i < 3004; i++) { - results.add( - new ObjectWriteResponse(null, bucketName, null, objectName + "-" + i, null, null)); - } - List existingObject = createObjects(bucketName, 1, 0); - results.addAll(existingObject); - testRemoveObjects(testTags, results); - try { - client.statObject( - StatObjectArgs.builder() - .bucket(bucketName) - .object(existingObject.get(0).object()) - .build()); - handleException( - methodName, - testTags, - startTime, - new Exception("object " + existingObject.get(0).object() + " still exist")); - } catch (ErrorResponseException e) { - if (!e.errorResponse().code().equals("NoSuchKey")) { - throw e; - } - } - } - - public static void testGetPresignedUrl(GetPresignedObjectUrlArgs args, String expectedChecksum) - throws Exception { - String urlString = client.getPresignedObjectUrl(args); - byte[] data = readObject(urlString); - String checksum = getSha256Sum(new ByteArrayInputStream(data), data.length); - Assert.assertEquals( - "content checksum differs; expected = " + expectedChecksum + ", got = " + checksum, - expectedChecksum, - checksum); - } - - public static void testGetPresignedObjectUrlForGet() throws Exception { - String methodName = "getPresignedObjectUrl()"; - String testTags = null; - long startTime = System.currentTimeMillis(); - try { - String expectedChecksum = getSha256Sum(new ContentInputStream(1 * KB), 1 * KB); - String objectName = getRandomName(); - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - try { - testTags = "[GET]"; - testGetPresignedUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket(bucketName) - .object(objectName) - .build(), - expectedChecksum); - - testTags = "[GET, expiry]"; - testGetPresignedUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket(bucketName) - .object(objectName) - .expiry(1, TimeUnit.DAYS) - .build(), - expectedChecksum); - - testTags = "[GET, expiry, query params]"; - Map queryParams = new HashMap<>(); - queryParams.put("response-content-type", "application/json"); - testGetPresignedUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket(bucketName) - .object(objectName) - .expiry(1, TimeUnit.DAYS) - .extraQueryParams(queryParams) - .build(), - expectedChecksum); - - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testPutPresignedUrl( - String testTags, byte[] data, String expectedChecksum, GetPresignedObjectUrlArgs args) - throws Exception { - String methodName = "getPresignedObjectUrl()"; - long startTime = System.currentTimeMillis(); - try { - String urlString = client.getPresignedObjectUrl(args); - try { - writeObject(urlString, data); - InputStream is = - client.getObject( - GetObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - data = readAllBytes(is); - String checksum = getSha256Sum(new ByteArrayInputStream(data), data.length); - Assert.assertEquals( - "content checksum differs; expected = " + expectedChecksum + ", got = " + checksum, - expectedChecksum, - checksum); - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testGetPresignedObjectUrlForPut() throws Exception { - byte[] data = "hello, world".getBytes(StandardCharsets.UTF_8); - String expectedChecksum = getSha256Sum(new ByteArrayInputStream(data), data.length); - String objectName = getRandomName(); - - testPutPresignedUrl( - "[PUT]", - data, - expectedChecksum, - GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) - .bucket(bucketName) - .object(objectName) - .build()); - - testPutPresignedUrl( - "[PUT, expiry]", - data, - expectedChecksum, - GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) - .bucket(bucketName) - .object(objectName) - .expiry(1, TimeUnit.DAYS) - .build()); - } - - public static void getPresignedObjectUrl() throws Exception { - if (!mintEnv) { - System.out.println("getPresignedObjectUrl()"); - } - - testGetPresignedObjectUrlForGet(); - testGetPresignedObjectUrlForPut(); - } - - public static void getPresignedPostFormData() throws Exception { - String methodName = "getPresignedPostFormData()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - - PostPolicy policy = new PostPolicy(bucketName, ZonedDateTime.now().plusDays(7)); - policy.addEqualsCondition("key", objectName); - policy.addEqualsCondition("content-type", "image/png"); - policy.addContentLengthRangeCondition(1 * MB, 4 * MB); - Map formData = client.getPresignedPostFormData(policy); - - MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); - multipartBuilder.setType(MultipartBody.FORM); - for (Map.Entry entry : formData.entrySet()) { - multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue()); - } - multipartBuilder.addFormDataPart("key", objectName); - multipartBuilder.addFormDataPart("Content-Type", "image/png"); - multipartBuilder.addFormDataPart( - "file", - objectName, - RequestBody.create(readAllBytes(new ContentInputStream(1 * MB)), null)); - - Request.Builder requestBuilder = new Request.Builder(); - String urlString = - client.getPresignedObjectUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket(bucketName) - .object("x") - .build()); - urlString = urlString.split("\\?")[0]; // Remove query parameters. - // remove last two characters to get clean url string of bucket. - urlString = urlString.substring(0, urlString.length() - 2); - Request request = requestBuilder.url(urlString).post(multipartBuilder.build()).build(); - OkHttpClient transport = newHttpClient(); - Response response = transport.newCall(request).execute(); - Assert.assertNotNull("no response from server", response); - - try { - if (!response.isSuccessful()) { - String errorXml = response.body().string(); - throw new Exception( - "failed to upload object. Response: " + response + ", Error: " + errorXml); - } - } finally { - response.close(); - } - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void testCopyObject( - String testTags, ServerSideEncryption sse, CopyObjectArgs args, boolean negativeCase) - throws Exception { - String methodName = "copyObject()"; - long startTime = System.currentTimeMillis(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(args.source().bucket()).build()); - try { - PutObjectArgs.Builder builder = - PutObjectArgs.builder().bucket(args.source().bucket()).object(args.source().object()) - .stream(new ContentInputStream(1 * KB), 1 * KB, -1); - if (sse != null) { - builder.sse(sse); - } - client.putObject(builder.build()); - - if (negativeCase) { - try { - client.copyObject(args); - } catch (ErrorResponseException e) { - if (!e.errorResponse().code().equals("PreconditionFailed")) { - throw e; - } - } - } else { - client.copyObject(args); - - ServerSideEncryptionCustomerKey ssec = null; - if (sse instanceof ServerSideEncryptionCustomerKey) { - ssec = (ServerSideEncryptionCustomerKey) sse; - } - client.statObject( - StatObjectArgs.builder() - .bucket(args.bucket()) - .object(args.object()) - .ssec(ssec) - .build()); - } - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder() - .bucket(args.source().bucket()) - .object(args.source().object()) - .build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(args.source().bucket()).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testCopyObjectMatchETag() throws Exception { - String methodName = "copyObject()"; - String testTags = "[match etag]"; - long startTime = System.currentTimeMillis(); - String srcBucketName = getRandomName(); - String srcObjectName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); - try { - ObjectWriteResponse result = - client.putObject( - PutObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - client.copyObject( - CopyObjectArgs.builder() - .bucket(bucketName) - .object(srcObjectName + "-copy") - .source( - CopySource.builder() - .bucket(srcBucketName) - .object(srcObjectName) - .matchETag(result.etag()) - .build()) - .build()); - - client.statObject( - StatObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); - - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testCopyObjectMetadataReplace() throws Exception { - String methodName = "copyObject()"; - String testTags = "[metadata replace]"; - long startTime = System.currentTimeMillis(); - String srcBucketName = getRandomName(); - String srcObjectName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); - try { - client.putObject( - PutObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - Map headers = new HashMap<>(); - headers.put("Content-Type", customContentType); - headers.put("X-Amz-Meta-My-Project", "Project One"); - client.copyObject( - CopyObjectArgs.builder() - .bucket(bucketName) - .object(srcObjectName + "-copy") - .source(CopySource.builder().bucket(srcBucketName).object(srcObjectName).build()) - .headers(headers) - .metadataDirective(Directive.REPLACE) - .build()); - - StatObjectResponse stat = - client.statObject( - StatObjectArgs.builder() - .bucket(bucketName) - .object(srcObjectName + "-copy") - .build()); - Assert.assertEquals( - "content type differs. expected: " + customContentType + ", got: " + stat.contentType(), - customContentType, - stat.contentType()); - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testCopyObjectEmptyMetadataReplace() throws Exception { - String methodName = "copyObject()"; - String testTags = "[empty metadata replace]"; - long startTime = System.currentTimeMillis(); - String srcBucketName = getRandomName(); - String srcObjectName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); - try { - Map headers = new HashMap<>(); - headers.put("Content-Type", customContentType); - headers.put("X-Amz-Meta-My-Project", "Project One"); - client.putObject( - PutObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .headers(headers) - .build()); - - client.copyObject( - CopyObjectArgs.builder() - .bucket(bucketName) - .object(srcObjectName + "-copy") - .source(CopySource.builder().bucket(srcBucketName).object(srcObjectName).build()) - .metadataDirective(Directive.REPLACE) - .build()); - - StatObjectResponse stat = - client.statObject( - StatObjectArgs.builder() - .bucket(bucketName) - .object(srcObjectName + "-copy") - .build()); - Assert.assertFalse( - "expected user metadata to be removed in new object", - stat.userMetadata().containsKey("My-Project")); - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void copyObject() throws Exception { - String methodName = "copyObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - String objectName = getRandomName(); - testCopyObject( - "[basic check]", - null, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .source(CopySource.builder().bucket(getRandomName()).object(objectName).build()) - .build(), - false); - - if (isQuickTest) { - return; - } - - testCopyObject( - "[negative match etag]", - null, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .source( - CopySource.builder() - .bucket(getRandomName()) - .object(getRandomName()) - .matchETag("invalid-etag") - .build()) - .build(), - true); - - testCopyObjectMatchETag(); - - testCopyObject( - "[not match etag]", - null, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .source( - CopySource.builder() - .bucket(getRandomName()) - .object(getRandomName()) - .notMatchETag("not-etag-of-source-object") - .build()) - .build(), - false); - - testCopyObject( - "[modified since]", - null, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .source( - CopySource.builder() - .bucket(getRandomName()) - .object(getRandomName()) - .modifiedSince(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)) - .build()) - .build(), - false); - - testCopyObject( - "[negative unmodified since]", - null, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .source( - CopySource.builder() - .bucket(getRandomName()) - .object(getRandomName()) - .unmodifiedSince(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)) - .build()) - .build(), - true); - - testCopyObjectMetadataReplace(); - testCopyObjectEmptyMetadataReplace(); - - testCopyObject( - "[SSE-S3]", - sseS3, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sse(sseS3) - .source(CopySource.builder().bucket(getRandomName()).object(getRandomName()).build()) - .build(), - false); - - if (!isSecureEndpoint) { - mintIgnoredLog(methodName, "[SSE-C]", System.currentTimeMillis()); - mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); - return; - } - - testCopyObject( - "[SSE-C]", - ssec, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sse(ssec) - .source( - CopySource.builder() - .bucket(getRandomName()) - .object(getRandomName()) - .ssec(ssec) - .build()) - .build(), - false); - - if (sseKms == null) { - mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); - return; - } - - testCopyObject( - "[SSE-KMS]", - sseKms, - CopyObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sse(sseKms) - .source(CopySource.builder().bucket(getRandomName()).object(getRandomName()).build()) - .build(), - false); - } - - public static void testComposeObject(String testTags, ComposeObjectArgs args) throws Exception { - String methodName = "composeObject()"; - long startTime = System.currentTimeMillis(); - try { - client.composeObject(args); - client.removeObject( - RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static List createComposeSourceList(ComposeSource... sources) { - return Arrays.asList(sources); - } - - public static void composeObjectTests(String object1Mb, String object6Mb, String object6MbSsec) - throws Exception { - testComposeObject( - "[single source]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder().bucket(bucketName).object(object1Mb).build())) - .build()); - - testComposeObject( - "[single source with offset]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder() - .bucket(bucketName) - .object(object1Mb) - .offset(2L * KB) - .build())) - .build()); - - testComposeObject( - "[single source with offset and length]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder() - .bucket(bucketName) - .object(object1Mb) - .offset(2L * KB) - .length(5L * KB) - .build())) - .build()); - - testComposeObject( - "[single multipart source]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder().bucket(bucketName).object(object6Mb).build())) - .build()); - - testComposeObject( - "[two multipart source]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder().bucket(bucketName).object(object6Mb).build(), - ComposeSource.builder().bucket(bucketName).object(object6Mb).build())) - .build()); - - testComposeObject( - "[two multipart sources with offset and length]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder() - .bucket(bucketName) - .object(object6Mb) - .offset(10L) - .length(6291436L) - .build(), - ComposeSource.builder().bucket(bucketName).object(object6Mb).build())) - .build()); - - if (isQuickTest) { - return; - } - - if (!isSecureEndpoint) { - return; - } - - testComposeObject( - "[two SSE-C multipart sources]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sse(ssec) - .sources( - createComposeSourceList( - ComposeSource.builder() - .bucket(bucketName) - .object(object6MbSsec) - .ssec(ssec) - .build(), - ComposeSource.builder() - .bucket(bucketName) - .object(object6MbSsec) - .ssec(ssec) - .build())) - .build()); - - testComposeObject( - "[two multipart sources with one SSE-C]", - ComposeObjectArgs.builder() - .bucket(bucketName) - .object(getRandomName()) - .sources( - createComposeSourceList( - ComposeSource.builder() - .bucket(bucketName) - .object(object6MbSsec) - .ssec(ssec) - .build(), - ComposeSource.builder().bucket(bucketName).object(object6Mb).build())) - .build()); - } - - public static void composeObject() throws Exception { - String methodName = "composeObject()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - List createdObjects = new LinkedList<>(); - - try { - String object1Mb = null; - String object6Mb = null; - String object6MbSsec = null; - try { - ObjectWriteResponse response; - response = - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(1 * MB), 1 * MB, -1) - .build()); - createdObjects.add(response); - object1Mb = response.object(); - - response = - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(6 * MB), 6 * MB, -1) - .build()); - createdObjects.add(response); - object6Mb = response.object(); - - if (isSecureEndpoint) { - response = - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( - new ContentInputStream(6 * MB), 6 * MB, -1) - .sse(ssec) - .build()); - createdObjects.add(response); - object6MbSsec = response.object(); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - - composeObjectTests(object1Mb, object6Mb, object6MbSsec); - } finally { - removeObjects(bucketName, createdObjects); - } - } - - public static void checkObjectLegalHold(String bucketName, String objectName, boolean enableCheck) - throws Exception { - if (enableCheck) { - client.enableObjectLegalHold( - EnableObjectLegalHoldArgs.builder().bucket(bucketName).object(objectName).build()); - } else { - client.disableObjectLegalHold( - DisableObjectLegalHoldArgs.builder().bucket(bucketName).object(objectName).build()); - } - - boolean result = - client.isObjectLegalHoldEnabled( - IsObjectLegalHoldEnabledArgs.builder().bucket(bucketName).object(objectName).build()); - Assert.assertEquals( - "object legal hold: expected: " + enableCheck + ", got: " + result, result, enableCheck); - } - - public static void enableObjectLegalHold() throws Exception { - if (bucketNameWithLock == null) return; - - String methodName = "enableObjectLegalHold()"; - if (!mintEnv) { - System.out.println(methodName); - } - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - ObjectWriteResponse objectInfo = null; - try { - try { - objectInfo = - client.putObject( - PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - checkObjectLegalHold(bucketNameWithLock, objectName, true); - client.disableObjectLegalHold( - DisableObjectLegalHoldArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .build()); - mintSuccessLog(methodName, null, startTime); - } finally { - if (objectInfo != null) { - client.removeObject( - RemoveObjectArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .versionId(objectInfo.versionId()) - .build()); - } - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void disableObjectLegalHold() throws Exception { - if (bucketNameWithLock == null) return; - - String methodName = "disableObjectLegalHold()"; - if (!mintEnv) { - System.out.println(methodName); - } - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - ObjectWriteResponse objectInfo = null; - try { - try { - objectInfo = - client.putObject( - PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - checkObjectLegalHold(bucketNameWithLock, objectName, false); - client.enableObjectLegalHold( - EnableObjectLegalHoldArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .build()); - checkObjectLegalHold(bucketNameWithLock, objectName, false); - mintSuccessLog(methodName, null, startTime); - } finally { - if (objectInfo != null) { - client.removeObject( - RemoveObjectArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .versionId(objectInfo.versionId()) - .build()); - } - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void isObjectLegalHoldEnabled() throws Exception { - if (bucketNameWithLock == null) return; - - String methodName = "isObjectLegalHoldEnabled()"; - if (!mintEnv) { - System.out.println(methodName); - } - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - ObjectWriteResponse objectInfo = null; - try { - try { - objectInfo = - client.putObject( - PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - boolean result = - client.isObjectLegalHoldEnabled( - IsObjectLegalHoldEnabledArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .build()); - Assert.assertFalse("object legal hold: expected: false, got: " + result, result); - checkObjectLegalHold(bucketNameWithLock, objectName, true); - checkObjectLegalHold(bucketNameWithLock, objectName, false); - mintSuccessLog(methodName, null, startTime); - } finally { - if (objectInfo != null) { - client.removeObject( - RemoveObjectArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .versionId(objectInfo.versionId()) - .build()); - } - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setObjectLockConfiguration() throws Exception { - String methodName = "setObjectLockConfiguration()"; - String testTags = "[COMPLIANCE, 10 days]"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); - try { - ObjectLockConfiguration config = - new ObjectLockConfiguration(RetentionMode.COMPLIANCE, new RetentionDurationDays(10)); - client.setObjectLockConfiguration( - SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build()); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - mintSuccessLog(methodName, testTags, startTime); - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void testGetObjectLockConfiguration( - String bucketName, RetentionMode mode, RetentionDuration duration) throws Exception { - ObjectLockConfiguration expectedConfig = new ObjectLockConfiguration(mode, duration); - client.setObjectLockConfiguration( - SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(expectedConfig).build()); - ObjectLockConfiguration config = - client.getObjectLockConfiguration( - GetObjectLockConfigurationArgs.builder().bucket(bucketName).build()); - Assert.assertEquals( - "retention mode: expected: " + expectedConfig.mode() + ", got: " + config.mode(), - config.mode(), - expectedConfig.mode()); - Assert.assertFalse( - "retention duration: " + expectedConfig.duration() + ", got: " + config.duration(), - config.duration().unit() != expectedConfig.duration().unit() - || config.duration().duration() != expectedConfig.duration().duration()); - } - - public static void getObjectLockConfiguration() throws Exception { - String methodName = "getObjectLockConfiguration()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); - try { - testGetObjectLockConfiguration( - bucketName, RetentionMode.COMPLIANCE, new RetentionDurationDays(10)); - testGetObjectLockConfiguration( - bucketName, RetentionMode.GOVERNANCE, new RetentionDurationYears(1)); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteObjectLockConfiguration() throws Exception { - String methodName = "deleteObjectLockConfiguration()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); - try { - client.deleteObjectLockConfiguration( - DeleteObjectLockConfigurationArgs.builder().bucket(bucketName).build()); - ObjectLockConfiguration config = - new ObjectLockConfiguration(RetentionMode.COMPLIANCE, new RetentionDurationDays(10)); - client.setObjectLockConfiguration( - SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build()); - client.deleteObjectLockConfiguration( - DeleteObjectLockConfigurationArgs.builder().bucket(bucketName).build()); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setObjectRetention() throws Exception { - if (bucketNameWithLock == null) return; - - String methodName = "setObjectRetention()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - ObjectWriteResponse objectInfo = null; - try { - try { - objectInfo = - client.putObject( - PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - client.setObjectRetention( - SetObjectRetentionArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .config( - new Retention( - RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(1))) - .build()); - - client.setObjectRetention( - SetObjectRetentionArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .config(new Retention()) - .bypassGovernanceMode(true) - .build()); - } finally { - if (objectInfo != null) { - client.removeObject( - RemoveObjectArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .versionId(objectInfo.versionId()) - .build()); - } - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void testGetObjectRetention(SetObjectRetentionArgs args) throws Exception { - client.setObjectRetention(args); - Retention config = - client.getObjectRetention( - GetObjectRetentionArgs.builder().bucket(args.bucket()).object(args.object()).build()); - - if (args.config().mode() == null) { - Assert.assertFalse( - "retention mode: expected: , got: " + config.mode(), - config != null && config.mode() != null); - } else { - Assert.assertEquals( - "retention mode: expected: " + args.config().mode() + ", got: " + config.mode(), - args.config().mode(), - config.mode()); - } - - ZonedDateTime expectedDate = args.config().retainUntilDate(); - ZonedDateTime date = (config == null) ? null : config.retainUntilDate(); - - if (expectedDate == null) { - Assert.assertNull("retention retain-until-date: expected: , got: " + date, date); - } else { - Assert.assertEquals( - "retention retain-until-date: expected: " - + expectedDate.withNano(0) - + ", got: " - + date.withNano(0), - date.withNano(0), - expectedDate.withNano(0)); - } - } - - public static void getObjectRetention() throws Exception { - if (bucketNameWithLock == null) return; - - String methodName = "getObjectRetention()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - ObjectWriteResponse objectInfo = null; - try { - try { - objectInfo = - client.putObject( - PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - testGetObjectRetention( - SetObjectRetentionArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .config( - new Retention( - RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(3))) - .build()); - - // Check shortening retention until period - testGetObjectRetention( - SetObjectRetentionArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .config( - new Retention( - RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(1))) - .bypassGovernanceMode(true) - .build()); - - // Check empty retention. - // Enable below test when minio server release has a fix. - // testGetObjectRetention( - // SetObjectRetentionArgs.builder() - // .bucket(bucketNameWithLock) - // .object(objectName) - // .config(new Retention()) - // .bypassGovernanceMode(true) - // .build()); - } finally { - if (objectInfo != null) { - client.removeObject( - RemoveObjectArgs.builder() - .bucket(bucketNameWithLock) - .object(objectName) - .versionId(objectInfo.versionId()) - .bypassGovernanceMode(true) - .build()); - } - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketPolicy() throws Exception { - String methodName = "getBucketPolicy()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - String config = - client.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build()); - Assert.assertTrue("policy: expected: \"\", got: " + config, config.isEmpty()); - String policy = - "{'Version':'2012-10-17','Statement':[{'Action':['s3:GetObject'],'Effect':'Allow'," - + "'Principal':{'AWS':['*']},'Resource':['arn:aws:s3:::" - + bucketName - + "/myobject*'],'Sid':''}]}"; - policy = policy.replaceAll("'", "\""); - client.setBucketPolicy( - SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build()); - client.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setBucketPolicy() throws Exception { - String methodName = "setBucketPolicy()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - String policy = - "{'Version':'2012-10-17','Statement':[{'Action':['s3:GetObject'],'Effect':'Allow'," - + "'Principal':{'AWS':['*']},'Resource':['arn:aws:s3:::" - + bucketName - + "/myobject*'],'Sid':''}]}"; - policy = policy.replaceAll("'", "\""); - client.setBucketPolicy( - SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteBucketPolicy() throws Exception { - String methodName = "deleteBucketPolicy()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - client.deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket(bucketName).build()); - - String policy = - "{'Version':'2012-10-17','Statement':[{'Action':['s3:GetObject'],'Effect':'Allow'," - + "'Principal':{'AWS':['*']},'Resource':['arn:aws:s3:::" - + bucketName - + "/myobject*'],'Sid':''}]}"; - policy = policy.replaceAll("'", "\""); - client.setBucketPolicy( - SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build()); - client.deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket(bucketName).build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void testSetBucketLifecycle(String bucketName, LifecycleRule... rules) - throws Exception { - LifecycleConfiguration config = new LifecycleConfiguration(Arrays.asList(rules)); - client.setBucketLifecycle( - SetBucketLifecycleArgs.builder().bucket(bucketName).config(config).build()); - } - - public static void setBucketLifecycle() throws Exception { - String methodName = "setBucketLifecycle()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - testSetBucketLifecycle( - bucketName, - new LifecycleRule( - Status.ENABLED, - null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), - "rule2", - null, - null, - null)); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteBucketLifecycle() throws Exception { - String methodName = "deleteBucketLifecycle()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - client.deleteBucketLifecycle( - DeleteBucketLifecycleArgs.builder().bucket(bucketName).build()); - testSetBucketLifecycle( - bucketName, - new LifecycleRule( - Status.ENABLED, - null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), - "rule2", - null, - null, - null)); - client.deleteBucketLifecycle( - DeleteBucketLifecycleArgs.builder().bucket(bucketName).build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketLifecycle() throws Exception { - String methodName = "getBucketLifecycle()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - LifecycleConfiguration config = - client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); - Assert.assertNull("config: expected: , got: ", config); - testSetBucketLifecycle( - bucketName, - new LifecycleRule( - Status.ENABLED, - null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), - "rule2", - null, - null, - null)); - config = - client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); - Assert.assertNotNull("config: expected: , got: ", config); - List rules = config.rules(); - Assert.assertEquals( - "config.rules().size(): expected: 1, got: " + config.rules().size(), - 1, - config.rules().size()); - LifecycleRule rule = rules.get(0); - Assert.assertEquals( - "rule.status(): expected: " + Status.ENABLED + ", got: " + rule.status(), - rule.status(), - Status.ENABLED); - Assert.assertNotNull( - "rule.expiration(): expected: , got: ", rule.expiration()); - Assert.assertEquals( - "rule.expiration().days(): expected: 365, got: " + rule.expiration().days(), - rule.expiration().days(), - Integer.valueOf(365)); - Assert.assertNotNull("rule.filter(): expected: , got: ", rule.filter()); - Assert.assertEquals( - "rule.filter().prefix(): expected: logs/, got: " + rule.filter().prefix(), - "logs/", - rule.filter().prefix()); - Assert.assertEquals("rule.id(): expected: rule2, got: " + rule.id(), "rule2", rule.id()); - - testSetBucketLifecycle( - bucketName, - new LifecycleRule( - Status.ENABLED, - null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter(""), - null, - null, - null, - null)); - config = - client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); - Assert.assertNotNull("config: expected: , got: ", config); - Assert.assertEquals( - "config.rules().size(): expected: 1, got: " + config.rules().size(), - config.rules().size(), - 1); - Assert.assertNotNull( - "rule.filter(): expected: , got: ", config.rules().get(0).filter()); - Assert.assertEquals( - "rule.filter().prefix(): expected: , got: " - + config.rules().get(0).filter().prefix(), - "", - config.rules().get(0).filter().prefix()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setBucketNotification() throws Exception { - String methodName = "setBucketNotification()"; - long startTime = System.currentTimeMillis(); - if (sqsArn == null) { - mintIgnoredLog(methodName, null, startTime); - return; - } - - if (!mintEnv) { - System.out.println(methodName); - } - - try { - String bucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); - try { - List eventList = new LinkedList<>(); - eventList.add(EventType.OBJECT_CREATED_PUT); - eventList.add(EventType.OBJECT_CREATED_COPY); - QueueConfiguration queueConfig = new QueueConfiguration(); - queueConfig.setQueue(sqsArn); - queueConfig.setEvents(eventList); - queueConfig.setPrefixRule("images"); - queueConfig.setSuffixRule("pg"); - - List queueConfigList = new LinkedList<>(); - queueConfigList.add(queueConfig); - - NotificationConfiguration config = new NotificationConfiguration(); - config.setQueueConfigurationList(queueConfigList); - - client.setBucketNotification( - SetBucketNotificationArgs.builder().bucket(bucketName).config(config).build()); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketNotification() throws Exception { - String methodName = "getBucketNotification()"; - long startTime = System.currentTimeMillis(); - if (sqsArn == null) { - mintIgnoredLog(methodName, null, startTime); - return; - } - - if (!mintEnv) { - System.out.println(methodName); - } - - try { - String bucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); - try { - List eventList = new LinkedList<>(); - eventList.add(EventType.OBJECT_CREATED_PUT); - QueueConfiguration queueConfig = new QueueConfiguration(); - queueConfig.setQueue(sqsArn); - queueConfig.setEvents(eventList); - - List queueConfigList = new LinkedList<>(); - queueConfigList.add(queueConfig); - - NotificationConfiguration expectedConfig = new NotificationConfiguration(); - expectedConfig.setQueueConfigurationList(queueConfigList); - - client.setBucketNotification( - SetBucketNotificationArgs.builder().bucket(bucketName).config(expectedConfig).build()); - - NotificationConfiguration config = - client.getBucketNotification( - GetBucketNotificationArgs.builder().bucket(bucketName).build()); - - if (config.queueConfigurationList().size() != 1 - || !sqsArn.equals(config.queueConfigurationList().get(0).queue()) - || config.queueConfigurationList().get(0).events().size() != 1 - || config.queueConfigurationList().get(0).events().get(0) - != EventType.OBJECT_CREATED_PUT) { - System.out.println( - "config: expected: " + Xml.marshal(expectedConfig) + ", got: " + Xml.marshal(config)); - } - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteBucketNotification() throws Exception { - String methodName = "deleteBucketNotification()"; - long startTime = System.currentTimeMillis(); - if (sqsArn == null) { - mintIgnoredLog(methodName, null, startTime); - return; - } - - if (!mintEnv) { - System.out.println(methodName); - } - - try { - String bucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); - try { - List eventList = new LinkedList<>(); - eventList.add(EventType.OBJECT_CREATED_PUT); - eventList.add(EventType.OBJECT_CREATED_COPY); - QueueConfiguration queueConfig = new QueueConfiguration(); - queueConfig.setQueue(sqsArn); - queueConfig.setEvents(eventList); - queueConfig.setPrefixRule("images"); - queueConfig.setSuffixRule("pg"); - - List queueConfigList = new LinkedList<>(); - queueConfigList.add(queueConfig); - - NotificationConfiguration config = new NotificationConfiguration(); - config.setQueueConfigurationList(queueConfigList); - - client.setBucketNotification( - SetBucketNotificationArgs.builder().bucket(bucketName).config(config).build()); - - client.deleteBucketNotification( - DeleteBucketNotificationArgs.builder().bucket(bucketName).build()); - - config = - client.getBucketNotification( - GetBucketNotificationArgs.builder().bucket(bucketName).build()); - if (config.queueConfigurationList().size() != 0) { - System.out.println("config: expected: , got: " + Xml.marshal(config)); - } - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void listenBucketNotification() throws Exception { - String methodName = "listenBucketNotification()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String file = createFile1Kb(); - String bucketName = getRandomName(); - CloseableIterator> ci = null; - String mintArgs = - "prefix=prefix, suffix=suffix, events={\"s3:ObjectCreated:*\", \"s3:ObjectAccessed:*\"}"; - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); - - String[] events = {"s3:ObjectCreated:*", "s3:ObjectAccessed:*"}; - ci = - client.listenBucketNotification( - ListenBucketNotificationArgs.builder() - .bucket(bucketName) - .prefix("prefix") - .suffix("suffix") - .events(events) - .build()); - - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object("prefix-random-suffix").stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - - while (ci.hasNext()) { - NotificationRecords records = ci.next().get(); - if (records.events().size() == 0) { - continue; - } - - boolean found = false; - for (Event event : records.events()) { - if (event.objectName().equals("prefix-random-suffix")) { - found = true; - break; - } - } - - if (found) { - break; - } - } - - mintSuccessLog(methodName, mintArgs, startTime); - } catch (Exception e) { - handleException(methodName, mintArgs, startTime, e); - } finally { - if (ci != null) { - ci.close(); - } - - Files.delete(Paths.get(file)); - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object("prefix-random-suffix").build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } - - public static void selectObjectContent() throws Exception { - String methodName = "selectObjectContent()"; - String sqlExpression = "select * from S3Object"; - String testArgs = "[sqlExpression: " + sqlExpression + ", requestProgress: true]"; - - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - SelectResponseStream responseStream = null; - try { - String expectedResult = - "1997,Ford,E350,\"ac, abs, moon\",3000.00\n" - + "1999,Chevy,\"Venture \"\"Extended Edition\"\"\",,4900.00\n" - + "1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00\n" - + "1996,Jeep,Grand Cherokee,\"MUST SELL!\n" - + "air, moon roof, loaded\",4799.00\n"; - byte[] data = - ("Year,Make,Model,Description,Price\n" + expectedResult).getBytes(StandardCharsets.UTF_8); - ByteArrayInputStream bais = new ByteArrayInputStream(data); - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - bais, data.length, -1) - .build()); - - InputSerialization is = - new InputSerialization(null, false, null, null, FileHeaderInfo.USE, null, null, null); - OutputSerialization os = - new OutputSerialization(null, null, null, QuoteFields.ASNEEDED, null); - - responseStream = - client.selectObjectContent( - SelectObjectContentArgs.builder() - .bucket(bucketName) - .object(objectName) - .sqlExpression(sqlExpression) - .inputSerialization(is) - .outputSerialization(os) - .requestProgress(true) - .build()); - - String result = new String(readAllBytes(responseStream), StandardCharsets.UTF_8); - Assert.assertEquals( - "result mismatch; expected: " + expectedResult + ", got: " + result, - result, - expectedResult); - - Stats stats = responseStream.stats(); - Assert.assertNotNull("stats is null", stats); - Assert.assertEquals( - "stats.bytesScanned mismatch; expected: 258, got: " + stats.bytesScanned(), - stats.bytesScanned(), - 256); - Assert.assertEquals( - "stats.bytesProcessed mismatch; expected: 258, got: " + stats.bytesProcessed(), - stats.bytesProcessed(), - 256); - Assert.assertEquals( - "stats.bytesReturned mismatch; expected: 222, got: " + stats.bytesReturned(), - stats.bytesReturned(), - 222); - mintSuccessLog(methodName, testArgs, startTime); - } catch (Exception e) { - handleException(methodName, testArgs, startTime, e); - } finally { - if (responseStream != null) { - responseStream.close(); - } - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } - - public static void setBucketEncryption() throws Exception { - String methodName = "setBucketEncryption()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - client.setBucketEncryption( - SetBucketEncryptionArgs.builder() - .bucket(bucketName) - .config(SseConfiguration.newConfigWithSseS3Rule()) - .build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketEncryption() throws Exception { - String methodName = "getBucketEncryption()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - SseConfiguration config = - client.getBucketEncryption( - GetBucketEncryptionArgs.builder().bucket(bucketName).build()); - Assert.assertNull("rule: expected: , got: ", config.rule()); - client.setBucketEncryption( - SetBucketEncryptionArgs.builder() - .bucket(bucketName) - .config(SseConfiguration.newConfigWithSseS3Rule()) - .build()); - config = - client.getBucketEncryption( - GetBucketEncryptionArgs.builder().bucket(bucketName).build()); - Assert.assertNotNull("rule: expected: , got: ", config.rule()); - Assert.assertEquals( - "sse algorithm: expected: " - + SseAlgorithm.AES256 - + ", got: " - + config.rule().sseAlgorithm(), - config.rule().sseAlgorithm(), - SseAlgorithm.AES256); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteBucketEncryption() throws Exception { - String methodName = "deleteBucketEncryption()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - client.deleteBucketEncryption( - DeleteBucketEncryptionArgs.builder().bucket(bucketName).build()); - - client.setBucketEncryption( - SetBucketEncryptionArgs.builder() - .bucket(bucketName) - .config(SseConfiguration.newConfigWithSseS3Rule()) - .build()); - client.deleteBucketEncryption( - DeleteBucketEncryptionArgs.builder().bucket(bucketName).build()); - SseConfiguration config = - client.getBucketEncryption( - GetBucketEncryptionArgs.builder().bucket(bucketName).build()); - Assert.assertNull("rule: expected: , got: ", config.rule()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void testBucketCors(String methodName, boolean getTest, boolean deleteTest) - throws Exception { - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - CORSConfiguration expectedConfig = - new CORSConfiguration( - Arrays.asList( - new CORSConfiguration.CORSRule[] { - // Rule 1 - new CORSConfiguration.CORSRule( - Arrays.asList(new String[] {"*"}), // Allowed headers - Arrays.asList(new String[] {"PUT", "POST", "DELETE"}), // Allowed methods - Arrays.asList(new String[] {"http://www.example.com"}), // Allowed origins - Arrays.asList( - new String[] {"x-amz-server-side-encryption"}), // Expose headers - null, // ID - 3000), // Maximum age seconds - // Rule 2 - new CORSConfiguration.CORSRule( - null, // Allowed headers - Arrays.asList(new String[] {"GET"}), // Allowed methods - Arrays.asList(new String[] {"*"}), // Allowed origins - null, // Expose headers - null, // ID - null // Maximum age seconds - ) - })); - client.setBucketCors( - SetBucketCorsArgs.builder().bucket(bucketName).config(expectedConfig).build()); - if (getTest) { - CORSConfiguration config = - client.getBucketCors(GetBucketCorsArgs.builder().bucket(bucketName).build()); - Assert.assertEquals( - "cors: expected: " + expectedConfig + ", got: " + config, expectedConfig, config); - } - if (deleteTest) { - client.deleteBucketCors(DeleteBucketCorsArgs.builder().bucket(bucketName).build()); - } - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setBucketCors() throws Exception { - testBucketCors("setBucketCors()", false, false); - } - - public static void getBucketCors() throws Exception { - testBucketCors("getBucketCors()", true, false); - } - - public static void deleteBucketCors() throws Exception { - testBucketCors("deleteBucketCors()", false, true); - } - - public static void setBucketTags() throws Exception { - String methodName = "setBucketTags()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(map).build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketTags() throws Exception { - String methodName = "getBucketTags()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - Map map = new HashMap<>(); - Tags tags = client.getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build()); - Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); - - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(map).build()); - tags = client.getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build()); - Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteBucketTags() throws Exception { - String methodName = "deleteBucketTags()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String bucketName = getRandomName(); - try { - client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - try { - client.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket(bucketName).build()); - - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(map).build()); - client.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket(bucketName).build()); - Tags tags = client.getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build()); - Assert.assertTrue("tags: expected: " + ", got: " + tags.get(), tags.get().isEmpty()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setObjectTags() throws Exception { - String methodName = "setObjectTags()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - try { - try { - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.setObjectTags( - SetObjectTagsArgs.builder().bucket(bucketName).object(objectName).tags(map).build()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getObjectTags() throws Exception { - String methodName = "getObjectTags()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - try { - try { - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - Map map = new HashMap<>(); - Tags tags = - client.getObjectTags( - GetObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); - Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); - - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.setObjectTags( - SetObjectTagsArgs.builder().bucket(bucketName).object(objectName).tags(map).build()); - tags = - client.getObjectTags( - GetObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); - Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteObjectTags() throws Exception { - String methodName = "deleteObjectTags()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - try { - try { - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - client.deleteObjectTags( - DeleteObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); - - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.setObjectTags( - SetObjectTagsArgs.builder().bucket(bucketName).object(objectName).tags(map).build()); - client.deleteObjectTags( - DeleteObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); - Tags tags = - client.getObjectTags( - GetObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); - Assert.assertTrue("tags: expected: , got: " + tags.get(), tags.get().isEmpty()); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getObjectAcl() throws Exception { - String methodName = "getObjectAcl()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - try { - try { - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - AccessControlPolicy policy = - client.getObjectAcl( - GetObjectAclArgs.builder().bucket(bucketName).object(objectName).build()); - Assert.assertEquals( - "granteeType: expected: " - + GranteeType.CANONICAL_USER - + ", got: " - + policy.accessControlList().grants().get(0).grantee().type(), - policy.accessControlList().grants().get(0).grantee().type(), - GranteeType.CANONICAL_USER); - Assert.assertEquals( - "permission: expected: " - + Permission.FULL_CONTROL - + ", got: " - + policy.accessControlList().grants().get(0).permission(), - policy.accessControlList().grants().get(0).permission(), - Permission.FULL_CONTROL); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getObjectAttributes() throws Exception { - String methodName = "getObjectAttributes()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName = getRandomName(); - try { - try { - client.putObject( - PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( - new ContentInputStream(1 * KB), 1 * KB, -1) - .build()); - GetObjectAttributesResponse response = - client.getObjectAttributes( - GetObjectAttributesArgs.builder() - .bucket(bucketName) - .object(objectName) - .objectAttributes( - new String[] { - "ETag", "Checksum", "ObjectParts", "StorageClass", "ObjectSize" - }) - .build()); - Assert.assertTrue( - "objectSize: expected: " + (1 * KB) + ", got: " + response.result().objectSize(), - response.result().objectSize() == (1 * KB)); - Assert.assertTrue( - "partNumber: expected: 1, got: " - + response.result().objectParts().parts().get(0).partNumber(), - response.result().objectParts().parts().get(0).partNumber() == 1); - Assert.assertTrue( - "partSize: expected: " - + (1 * KB) - + ", got: " - + response.result().objectParts().parts().get(0).partSize(), - response.result().objectParts().parts().get(0).partSize() == (1 * KB)); - mintSuccessLog(methodName, null, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void setBucketReplication() throws Exception { - String methodName = "setBucketReplication()"; - if (!mintEnv) { - System.out.println(methodName); - } - - if (replicationSrcBucket == null || replicationRole == null || replicationBucketArn == null) { - mintIgnoredLog(methodName, "", System.currentTimeMillis()); - return; - } - - long startTime = System.currentTimeMillis(); - try { - Map tags = new HashMap<>(); - tags.put("key1", "value1"); - tags.put("key2", "value2"); - - ReplicationRule rule = - new ReplicationRule( - new DeleteMarkerReplication(Status.DISABLED), - new ReplicationDestination(null, null, replicationBucketArn, null, null, null, null), - null, - new RuleFilter(new AndOperator("TaxDocs", tags)), - "rule1", - null, - 1, - null, - Status.ENABLED); - - List rules = new LinkedList<>(); - rules.add(rule); - - ReplicationConfiguration config = new ReplicationConfiguration(replicationRole, rules); - - client.setBucketReplication( - SetBucketReplicationArgs.builder().bucket(replicationSrcBucket).config(config).build()); - client.deleteBucketReplication( - DeleteBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void getBucketReplication() throws Exception { - String methodName = "getBucketReplication()"; - if (!mintEnv) { - System.out.println(methodName); - } - - if (replicationSrcBucket == null || replicationRole == null || replicationBucketArn == null) { - mintIgnoredLog(methodName, "", System.currentTimeMillis()); - return; - } - - long startTime = System.currentTimeMillis(); - try { - ReplicationConfiguration config = - client.getBucketReplication( - GetBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - Assert.assertNull("config: expected: , got: ", config); - - Map tags = new HashMap<>(); - tags.put("key1", "value1"); - tags.put("key2", "value2"); - - ReplicationRule rule = - new ReplicationRule( - new DeleteMarkerReplication(Status.DISABLED), - new ReplicationDestination(null, null, replicationBucketArn, null, null, null, null), - null, - new RuleFilter(new AndOperator("TaxDocs", tags)), - "rule1", - null, - 1, - null, - Status.ENABLED); - - List rules = new LinkedList<>(); - rules.add(rule); - - config = new ReplicationConfiguration(replicationRole, rules); - client.setBucketReplication( - SetBucketReplicationArgs.builder().bucket(replicationSrcBucket).config(config).build()); - config = - client.getBucketReplication( - GetBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - Assert.assertNotNull("config: expected: , got: ", config); - client.deleteBucketReplication( - DeleteBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void deleteBucketReplication() throws Exception { - String methodName = "deleteBucketReplication()"; - if (!mintEnv) { - System.out.println(methodName); - } - - if (replicationSrcBucket == null || replicationRole == null || replicationBucketArn == null) { - mintIgnoredLog(methodName, "", System.currentTimeMillis()); - return; - } - - long startTime = System.currentTimeMillis(); - try { - client.deleteBucketReplication( - DeleteBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - - Map tags = new HashMap<>(); - tags.put("key1", "value1"); - tags.put("key2", "value2"); - - ReplicationRule rule = - new ReplicationRule( - new DeleteMarkerReplication(Status.DISABLED), - new ReplicationDestination(null, null, replicationBucketArn, null, null, null, null), - null, - new RuleFilter(new AndOperator("TaxDocs", tags)), - "rule1", - null, - 1, - null, - Status.ENABLED); - - List rules = new LinkedList<>(); - rules.add(rule); - - ReplicationConfiguration config = new ReplicationConfiguration(replicationRole, rules); - client.setBucketReplication( - SetBucketReplicationArgs.builder().bucket(replicationSrcBucket).config(config).build()); - client.deleteBucketReplication( - DeleteBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - config = - client.getBucketReplication( - GetBucketReplicationArgs.builder().bucket(replicationSrcBucket).build()); - Assert.assertNull("config: expected: , got: ", config); - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void testUploadSnowballObjects(String testTags, boolean compression) - throws Exception { - String methodName = "uploadSnowballObjects()"; - - long startTime = System.currentTimeMillis(); - String objectName1 = getRandomName(); - String objectName2 = getRandomName(); - try { - try { - List objects = new LinkedList(); - objects.add( - new SnowballObject( - objectName1, - new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)), - 5, - null)); - objects.add(new SnowballObject(objectName2, createFile1Kb())); - client.uploadSnowballObjects( - UploadSnowballObjectsArgs.builder() - .bucket(bucketName) - .objects(objects) - .compression(compression) - .build()); - - StatObjectResponse stat = - client.statObject( - StatObjectArgs.builder().bucket(bucketName).object(objectName1).build()); - Assert.assertEquals("object size: expected: 5, got: " + stat.size(), 5, stat.size()); - stat = - client.statObject( - StatObjectArgs.builder().bucket(bucketName).object(objectName2).build()); - Assert.assertEquals( - "object size: expected: " + KB + ", got: " + stat.size(), 1 * KB, stat.size()); - mintSuccessLog(methodName, testTags, startTime); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName1).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName2).build()); - } - } catch (Exception e) { - handleException(methodName, testTags, startTime, e); - } - } - - public static void uploadSnowballObjects() throws Exception { - String methodName = "uploadSnowballObjects()"; - if (!mintEnv) { - System.out.println(methodName); - } - - testUploadSnowballObjects("[no compression]", false); - testUploadSnowballObjects("[compression]", true); - } - - public static void putObjectFanOut() throws Exception { - String methodName = "putObjectFanOut()"; - if (!mintEnv) { - System.out.println(methodName); - } - - long startTime = System.currentTimeMillis(); - String objectName1 = getRandomName(); - String objectName2 = getRandomName(); - try { - try { - Map map = new HashMap<>(); - map.put("Project", "Project One"); - map.put("User", "jsmith"); - client.putObjectFanOut( - PutObjectFanOutArgs.builder().bucket(bucketName).stream( - new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)), 5) - .entries( - Arrays.asList( - new PutObjectFanOutEntry[] { - PutObjectFanOutEntry.builder().key(objectName1).userMetadata(map).build(), - PutObjectFanOutEntry.builder().key(objectName2).tags(map).build() - })) - .build()); - - StatObjectResponse stat = - client.statObject( - StatObjectArgs.builder().bucket(bucketName).object(objectName1).build()); - Assert.assertTrue( - "userMetadata: expected = " + map + ", got = " + stat.userMetadata(), - map.size() == stat.userMetadata().size() - && map.entrySet().stream() - .allMatch( - e -> - e.getValue() - .equals( - stat.userMetadata().get(e.getKey().toLowerCase(Locale.US))))); - - Tags tags = - client.getObjectTags( - GetObjectTagsArgs.builder().bucket(bucketName).object(objectName2).build()); - Assert.assertTrue( - "tags: expected = " + map + ", got = " + tags.get(), map.equals(tags.get())); - } finally { - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName1).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(bucketName).object(objectName2).build()); - } - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - public static void runBucketTests() throws Exception { - makeBucket(); - bucketExists(); - removeBucket(); - listBuckets(); - - setBucketVersioning(); - getBucketVersioning(); - - setObjectLockConfiguration(); - getObjectLockConfiguration(); - - setBucketEncryption(); - getBucketEncryption(); - deleteBucketEncryption(); - - setBucketCors(); - getBucketCors(); - deleteBucketCors(); - - setBucketTags(); - getBucketTags(); - deleteBucketTags(); - - setBucketPolicy(); - getBucketPolicy(); - deleteBucketPolicy(); - - setBucketLifecycle(); - getBucketLifecycle(); - deleteBucketLifecycle(); - - setBucketNotification(); - getBucketNotification(); - deleteBucketNotification(); - - setBucketReplication(); - getBucketReplication(); - deleteBucketReplication(); - - listenBucketNotification(); - } - - public static void runObjectTests() throws Exception { - listObjects(); - - setup(); - - putObject(); - getObject(); - removeObject(); - removeObjects(); - statObject(); - - copyObject(); - composeObject(); - uploadObject(); - downloadObject(); - - setObjectRetention(); - getObjectRetention(); - - getPresignedObjectUrl(); - getPresignedPostFormData(); - - enableObjectLegalHold(); - disableObjectLegalHold(); - isObjectLegalHoldEnabled(); - - selectObjectContent(); - - setObjectTags(); - getObjectTags(); - deleteObjectTags(); - - getObjectAcl(); - getObjectAttributes(); - - uploadSnowballObjects(); - putObjectFanOut(); - - teardown(); - } - - public static void runTests() throws Exception { - runBucketTests(); - runObjectTests(); - adminClientTests.runAdminTests(); - } - - public static boolean downloadMinio() throws IOException { - String url = "https://dl.min.io/server/minio/release/"; - if (OS.contains("linux")) { - url += "linux-amd64/minio"; - } else if (OS.contains("windows")) { - url += "windows-amd64/minio.exe"; - } else if (OS.contains("mac")) { - url += "darwin-amd64/minio"; - } else { - System.out.println("unknown operating system " + OS); - return false; - } - - File file = new File(MINIO_BINARY); - if (file.exists()) { - return true; - } - - System.out.println("downloading " + MINIO_BINARY + " binary"); - - Request.Builder requestBuilder = new Request.Builder(); - Request request = requestBuilder.url(HttpUrl.parse(url)).method("GET", null).build(); - OkHttpClient transport = newHttpClient(); - Response response = transport.newCall(request).execute(); - - try { - if (!response.isSuccessful()) { - System.out.println("failed to download binary " + MINIO_BINARY); - return false; - } +import io.minio.MinioClient; +import io.minio.admin.MinioAdminClient; - BufferedSink bufferedSink = Okio.buffer(Okio.sink(new File(MINIO_BINARY))); - bufferedSink.writeAll(response.body().source()); - bufferedSink.flush(); - bufferedSink.close(); - } finally { - response.close(); +public class FunctionalTest { + public static void runS3Tests(TestArgs args) throws Exception { + if (!args.MINT_ENV) System.out.println(">>> Running S3 tests:"); + new TestMinioClient( + args, + args.IS_QUICK_TEST, + MinioClient.builder() + .endpoint(args.endpoint) + .credentials(args.accessKey, args.secretKey) + .build()) + .runTests(); + + if (args.automated) { + if (!args.MINT_ENV) { + System.out.println(); + System.out.println(">>> Running S3 tests on TLS endpoint:"); + } + MinioClient client = + MinioClient.builder() + .endpoint(args.endpointTLS) + .credentials(args.accessKey, args.secretKey) + .build(); + client.ignoreCertCheck(); + new TestMinioClient(args, args.IS_QUICK_TEST, client).runTests(); } - if (!OS.contains("windows")) { - file.setExecutable(true); + if (!args.MINT_ENV) { + System.out.println(); + System.out.println(">>> Running quick tests specific region:"); + new TestMinioClient( + args, + true, + MinioClient.builder() + .endpoint(args.endpoint) + .credentials(args.accessKey, args.secretKey) + .region(args.region) + .build()) + .runTests(); } - - return true; } - public static Process runMinio(boolean tls) throws Exception { - File binaryPath = new File(new File(System.getProperty("user.dir")), MINIO_BINARY); - ProcessBuilder pb; - if (tls) { - pb = - new ProcessBuilder( - binaryPath.getPath(), - "server", - "--address", - ":9001", - "--certs-dir", - ".cfg/certs", - ".d{1...4}"); - } else { - pb = new ProcessBuilder(binaryPath.getPath(), "server", ".d{1...4}"); - } - - Map env = pb.environment(); - env.put("MINIO_ROOT_USER", "minio"); - env.put("MINIO_ROOT_PASSWORD", "minio123"); - env.put("MINIO_CI_CD", "1"); - // echo -n abcdefghijklmnopqrstuvwxyzABCDEF | base64 - - env.put("MINIO_KMS_SECRET_KEY", "my-minio-key:YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUY="); - env.put("MINIO_NOTIFY_WEBHOOK_ENABLE_miniojavatest", "on"); - env.put("MINIO_NOTIFY_WEBHOOK_ENDPOINT_miniojavatest", "http://example.org/"); - sqsArn = "arn:minio:sqs::miniojavatest:webhook"; - - pb.redirectErrorStream(true); - pb.redirectOutput(ProcessBuilder.Redirect.to(new File(MINIO_BINARY + ".log"))); - - if (tls) { - System.out.println("starting minio server in TLS"); - } else { - System.out.println("starting minio server"); + public static void runMinioAdminTests(TestArgs args) throws Exception { + if (!args.MINT_ENV) { + System.out.println(); + System.out.println(">>> Running MinIO admin API tests:"); + new TestMinioAdminClient( + args, + MinioAdminClient.builder() + .endpoint(args.endpoint) + .credentials(args.accessKey, args.secretKey) + .build()) + .runAdminTests(); } - Process p = pb.start(); - Thread.sleep(10 * 1000); // wait for 10 seconds to do real start. - return p; } - public static void runEndpointTests(boolean automated) throws Exception { - client = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build(); - MinioAdminClient adminClient = - MinioAdminClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build(); - adminClientTests = new TestMinioAdminClient(adminClient, mintEnv); - // Enable trace for debugging. - // client.traceOn(System.out); - if (!mintEnv) System.out.println(">>> Running tests:"); - FunctionalTest.runTests(); - - if (automated) { - // Run tests on TLS endpoint - client = - MinioClient.builder().endpoint(endpointTLS).credentials(accessKey, secretKey).build(); - client.ignoreCertCheck(); - adminClient = - MinioAdminClient.builder() - .endpoint(endpointTLS) - .credentials(accessKey, secretKey) - .build(); - adminClient.ignoreCertCheck(); - adminClientTests = new TestMinioAdminClient(adminClient, mintEnv); - // Enable trace for debugging. - // client.traceOn(System.out); - if (!mintEnv) System.out.println(">>> Running tests on TLS endpoint:"); - isSecureEndpoint = true; - FunctionalTest.runTests(); - } - - if (!mintEnv) { - System.out.println(); - System.out.println(">>> Running tests for region:"); - isQuickTest = true; - isSecureEndpoint = endpoint.toLowerCase(Locale.US).contains("https://"); - // Get new bucket name to avoid minio azure gateway failure. - bucketName = getRandomName(); - bucketNameWithLock = getRandomName(); - client = - MinioClient.builder() - .endpoint(endpoint) - .credentials(accessKey, secretKey) - .region(region) - .build(); - adminClient = - MinioAdminClient.builder() - .endpoint(endpoint) - .credentials(accessKey, secretKey) - .region(region) - .build(); - adminClientTests = new TestMinioAdminClient(adminClient, mintEnv); - FunctionalTest.runTests(); - } + public static void runTests(TestArgs args) throws Exception { + runS3Tests(args); + runMinioAdminTests(args); } - /** main(). */ public static void main(String[] args) throws Exception { - String mintMode = System.getenv("MINT_MODE"); - mintEnv = (mintMode != null); - if (mintEnv) { - isQuickTest = !mintMode.equals("full"); - isRunOnFail = "1".equals(System.getenv("RUN_ON_FAIL")); - String dataDir = System.getenv("MINT_DATA_DIR"); - if (dataDir != null && !dataDir.equals("")) { - dataFile1Kb = Paths.get(dataDir, "datafile-1-kB"); - dataFile6Mb = Paths.get(dataDir, "datafile-6-MB"); - } + String endpoint = null; + String accessKey = null; + String secretKey = null; + String region = null; + if (args.length == 4) { + endpoint = args[0]; + accessKey = args[1]; + secretKey = args[2]; + region = args[3]; } - replicationSrcBucket = System.getenv("MINIO_JAVA_TEST_REPLICATION_SRC_BUCKET"); - replicationRole = System.getenv("MINIO_JAVA_TEST_REPLICATION_ROLE"); - replicationBucketArn = System.getenv("MINIO_JAVA_TEST_REPLICATION_BUCKET_ARN"); + TestArgs testArgs = new TestArgs(endpoint, accessKey, secretKey, region); Process minioProcess = null; Process minioProcessTLS = null; - - boolean automated = true; - String kmsKeyName = "my-minio-key"; if (args.length != 4) { - endpoint = "http://localhost:9000"; - endpointTLS = "https://localhost:9001"; - accessKey = "minio"; - secretKey = "minio123"; - region = "us-east-1"; - - if (!downloadMinio()) { + if (!TestArgs.downloadMinioServer()) { System.out.println("usage: FunctionalTest "); System.exit(-1); } - minioProcess = runMinio(false); + minioProcess = TestArgs.runMinioServer(false); try { int exitValue = minioProcess.exitValue(); System.out.println("minio server process exited with " + exitValue); System.out.println("usage: FunctionalTest "); System.exit(-1); } catch (IllegalThreadStateException e) { - ignore(); + TestArgs.ignore(); } - minioProcessTLS = runMinio(true); + minioProcessTLS = TestArgs.runMinioServer(true); try { int exitValue = minioProcessTLS.exitValue(); System.out.println("minio server process exited with " + exitValue); System.out.println("usage: FunctionalTest "); System.exit(-1); } catch (IllegalThreadStateException e) { - ignore(); + TestArgs.ignore(); } - } else { - kmsKeyName = System.getenv("MINIO_JAVA_TEST_KMS_KEY_NAME"); - if (kmsKeyName == null) { - kmsKeyName = System.getenv("MINT_KEY_ID"); - } - sqsArn = System.getenv("MINIO_JAVA_TEST_SQS_ARN"); - endpoint = args[0]; - accessKey = args[1]; - secretKey = args[2]; - region = args[3]; - automated = false; - } - - isSecureEndpoint = endpoint.toLowerCase(Locale.US).contains("https://"); - if (kmsKeyName != null) { - Map myContext = new HashMap<>(); - myContext.put("key1", "value1"); - sseKms = new ServerSideEncryptionKms(kmsKeyName, myContext); } int exitValue = 0; try { - runEndpointTests(automated); + runTests(testArgs); } catch (Exception e) { - if (!mintEnv) { - e.printStackTrace(); - } + if (!testArgs.MINT_ENV) e.printStackTrace(); exitValue = -1; } finally { - if (minioProcess != null) { - minioProcess.destroy(); - } - if (minioProcessTLS != null) { - minioProcessTLS.destroy(); - } + if (minioProcess != null) minioProcess.destroy(); + if (minioProcessTLS != null) minioProcessTLS.destroy(); } System.exit(exitValue); diff --git a/functional/MintLogger.java b/functional/MintLogger.java old mode 100755 new mode 100644 diff --git a/functional/TestArgs.java b/functional/TestArgs.java new file mode 100644 index 000000000..b0247b3bc --- /dev/null +++ b/functional/TestArgs.java @@ -0,0 +1,421 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2015-2021 MinIO, 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. + */ + +import static java.nio.file.StandardOpenOption.APPEND; +import static java.nio.file.StandardOpenOption.CREATE; + +import io.minio.Checksum; +import io.minio.Http; +import io.minio.ServerSideEncryption; +import io.minio.errors.ErrorResponseException; +import io.minio.errors.MinioException; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import javax.crypto.KeyGenerator; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okio.BufferedSink; +import okio.Okio; +import org.junit.Assert; + +@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "REC", + justification = "Allow catching super class Exception since it's tests") +public class TestArgs { + public static final String OS = System.getProperty("os.name").toLowerCase(Locale.US); + public static final String MINIO_BINARY = OS.contains("windows") ? "minio.exe" : "minio"; + public static final String PASS = "PASS"; + public static final String FAILED = "FAIL"; + public static final String IGNORED = "NA"; + public static final int KB = 1024; + public static final int MB = 1024 * 1024; + public static final Random RANDOM = new Random(new SecureRandom().nextLong()); + public static final String CUSTOM_CONTENT_TYPE = "application/javascript"; + public static final ServerSideEncryption SSE_S3 = new ServerSideEncryption.S3(); + public static final ServerSideEncryption.CustomerKey SSE_C; + public static final boolean MINT_ENV; + public static final boolean IS_QUICK_TEST; + public static final boolean IS_RUN_ON_FAIL; + public static final Path DATA_FILE_1KB; + public static final Path DATA_FILE_6MB; + public static final String REPLICATION_SRC_BUCKET; + public static final String REPLICATION_ROLE; + public static final String REPLICATION_BUCKET_ARN; + + static { + try { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + SSE_C = new ServerSideEncryption.CustomerKey(keyGen.generateKey()); + } catch (NoSuchAlgorithmException | MinioException e) { + throw new RuntimeException(e); + } + + String mintMode = System.getenv("MINT_MODE"); + String dataDir = System.getenv("MINT_DATA_DIR"); + MINT_ENV = mintMode != null; + IS_QUICK_TEST = MINT_ENV && !"full".equals(mintMode); + IS_RUN_ON_FAIL = MINT_ENV && "1".equals(System.getenv("RUN_ON_FAIL")); + DATA_FILE_1KB = + (MINT_ENV && dataDir != null && !dataDir.isEmpty()) + ? Paths.get(dataDir, "datafile-1-kB") + : null; + DATA_FILE_6MB = + (MINT_ENV && dataDir != null && !dataDir.isEmpty()) + ? Paths.get(dataDir, "datafile-6-MB") + : null; + REPLICATION_SRC_BUCKET = System.getenv("MINIO_JAVA_TEST_REPLICATION_SRC_BUCKET"); + REPLICATION_ROLE = System.getenv("MINIO_JAVA_TEST_REPLICATION_ROLE"); + REPLICATION_BUCKET_ARN = System.getenv("MINIO_JAVA_TEST_REPLICATION_BUCKET_ARN"); + } + + public boolean automated; + public String endpoint; + public String endpointTLS; + public String accessKey; + public String secretKey; + public String region; + public boolean isSecureEndpoint = false; + public String sqsArn = null; + public ServerSideEncryption sseKms = null; + + public TestArgs(TestArgs args) { + this.automated = args.automated; + this.endpoint = args.endpoint; + this.endpointTLS = args.endpointTLS; + this.accessKey = args.accessKey; + this.secretKey = args.secretKey; + this.region = args.region; + this.isSecureEndpoint = args.isSecureEndpoint; + this.sqsArn = args.sqsArn; + this.sseKms = args.sseKms; + } + + public TestArgs(String endpoint, String accessKey, String secretKey, String region) + throws MinioException { + this.automated = endpoint == null; + + String kmsKeyName = "my-minio-key"; + if (endpoint == null) { + this.endpoint = "http://localhost:9000"; + this.endpointTLS = "https://localhost:9001"; + this.accessKey = "minio"; + this.secretKey = "minio123"; + this.region = "us-east-1"; + this.sqsArn = "arn:minio:sqs::miniojavatest:webhook"; + } else { + if ((kmsKeyName = System.getenv("MINIO_JAVA_TEST_KMS_KEY_NAME")) == null) { + kmsKeyName = System.getenv("MINT_KEY_ID"); + } + this.sqsArn = System.getenv("MINIO_JAVA_TEST_SQS_ARN"); + this.endpoint = endpoint; + this.accessKey = accessKey; + this.secretKey = secretKey; + this.region = region; + } + this.isSecureEndpoint = this.endpoint.toLowerCase(Locale.US).contains("https://"); + + if (kmsKeyName != null) { + Map myContext = new HashMap<>(); + myContext.put("key1", "value1"); + this.sseKms = new ServerSideEncryption.KMS(kmsKeyName, myContext); + } + } + + public static OkHttpClient newHttpClient() { + try { + return Http.disableCertCheck(Http.newDefaultClient()); + } catch (MinioException e) { + throw new RuntimeException(e); + } + } + + /** Do no-op. */ + public static void ignore(Object... args) {} + + /** Create given sized file and returns its name. */ + public static String createFile(int size) throws IOException { + String filename = getRandomName(); + + try (OutputStream os = Files.newOutputStream(Paths.get(filename), CREATE, APPEND)) { + int totalBytesWritten = 0; + int bytesToWrite = 0; + byte[] buf = new byte[1 * MB]; + while (totalBytesWritten < size) { + RANDOM.nextBytes(buf); + bytesToWrite = size - totalBytesWritten; + if (bytesToWrite > buf.length) bytesToWrite = buf.length; + os.write(buf, 0, bytesToWrite); + totalBytesWritten += bytesToWrite; + } + } + + return filename; + } + + /** Create 1 KB temporary file. */ + public static String createFile1Kb() throws IOException { + if (MINT_ENV) { + String filename = getRandomName(); + Files.createSymbolicLink(Paths.get(filename).toAbsolutePath(), DATA_FILE_1KB); + return filename; + } + + return createFile(1 * KB); + } + + /** Create 6 MB temporary file. */ + public static String createFile6Mb() throws IOException { + if (MINT_ENV) { + String filename = getRandomName(); + Files.createSymbolicLink(Paths.get(filename).toAbsolutePath(), DATA_FILE_6MB); + return filename; + } + + return createFile(6 * MB); + } + + /** Generate random name. */ + public static String getRandomName() { + return "minio-java-test-" + new BigInteger(32, RANDOM).toString(32); + } + + /** Returns byte array contains all data in given InputStream. */ + public static byte[] readAllBytes(InputStream is) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int n; + byte[] data = new byte[16384]; + while ((n = is.read(data, 0, data.length)) != -1) buffer.write(data, 0, n); + return buffer.toByteArray(); + } + + /** Prints a success log entry in JSON format. */ + public static void mintSuccessLog(String function, String args, long startTime) { + if (MINT_ENV) { + System.out.println( + new MintLogger( + function, args, System.currentTimeMillis() - startTime, PASS, null, null, null)); + } + } + + /** Prints a failure log entry in JSON format. */ + public static void mintFailedLog( + String function, String args, long startTime, String message, String error) { + if (MINT_ENV) { + System.out.println( + new MintLogger( + function, + args, + System.currentTimeMillis() - startTime, + FAILED, + null, + message, + error)); + } + } + + /** Prints a ignore log entry in JSON format. */ + public static void mintIgnoredLog(String function, String args, long startTime) { + if (MINT_ENV) { + System.out.println( + new MintLogger( + function, args, System.currentTimeMillis() - startTime, IGNORED, null, null, null)); + } + } + + /** Read object content of the given url. */ + public static byte[] readObject(String urlString) throws Exception { + Request request = + new Request.Builder().url(HttpUrl.parse(urlString)).method("GET", null).build(); + try (Response response = newHttpClient().newCall(request).execute()) { + if (response.isSuccessful()) return response.body().bytes(); + String errorXml = response.body().string(); + throw new Exception( + "failed to create object. Response: " + response + ", Response body: " + errorXml); + } + } + + /** Write data to given object url. */ + public static void writeObject(String urlString, byte[] dataBytes) throws Exception { + // Set header 'x-amz-acl' to 'bucket-owner-full-control', so objects created + // anonymously, can be downloaded by bucket owner in AWS S3. + Request request = + new Request.Builder() + .url(HttpUrl.parse(urlString)) + .method("PUT", RequestBody.create(dataBytes, null)) + .addHeader("x-amz-acl", "bucket-owner-full-control") + .build(); + try (Response response = newHttpClient().newCall(request).execute()) { + if (!response.isSuccessful()) { + String errorXml = response.body().string(); + throw new Exception( + "failed to create object. Response: " + response + ", Response body: " + errorXml); + } + } + } + + public static String getSha256Sum(InputStream stream, int len) throws Exception { + Checksum.Hasher hasher = Checksum.Algorithm.SHA256.hasher(); + // 16KiB buffer for optimization + byte[] buf = new byte[16384]; + int bytesToRead = buf.length; + int bytesRead = 0; + int totalBytesRead = 0; + while (totalBytesRead < len) { + if ((len - totalBytesRead) < bytesToRead) bytesToRead = len - totalBytesRead; + bytesRead = stream.read(buf, 0, bytesToRead); + Assert.assertFalse( + "data length mismatch. expected: " + len + ", got: " + totalBytesRead, bytesRead < 0); + if (bytesRead > 0) { + hasher.update(buf, 0, bytesRead); + totalBytesRead += bytesRead; + } + } + return Checksum.hexString(hasher.sum()).toLowerCase(Locale.US); + } + + public static void skipStream(InputStream stream, int len) throws Exception { + // 16KiB buffer for optimization + byte[] buf = new byte[16384]; + int bytesToRead = buf.length; + int bytesRead = 0; + int totalBytesRead = 0; + while (totalBytesRead < len) { + if ((len - totalBytesRead) < bytesToRead) bytesToRead = len - totalBytesRead; + bytesRead = stream.read(buf, 0, bytesToRead); + Assert.assertFalse( + "insufficient data. expected: " + len + ", got: " + totalBytesRead, bytesRead < 0); + if (bytesRead > 0) totalBytesRead += bytesRead; + } + } + + public static void handleException(String methodName, String args, long startTime, Exception e) + throws Exception { + if (e instanceof ErrorResponseException) { + if (((ErrorResponseException) e).errorResponse().code().equals("NotImplemented")) { + mintIgnoredLog(methodName, args, startTime); + return; + } + } + + if (MINT_ENV) { + mintFailedLog( + methodName, + args, + startTime, + null, + e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); + if (IS_RUN_ON_FAIL) return; + } else { + System.out.println(" " + methodName + " " + ((args == null) ? "" : args)); + } + + throw e; + } + + public static boolean downloadMinioServer() throws IOException { + String url = "https://dl.min.io/server/minio/release/"; + if (OS.contains("linux")) { + url += "linux-amd64/minio"; + } else if (OS.contains("windows")) { + url += "windows-amd64/minio.exe"; + } else if (OS.contains("mac")) { + url += "darwin-amd64/minio"; + } else { + System.out.println("unknown operating system " + OS); + return false; + } + + File file = new File(MINIO_BINARY); + if (file.exists()) return true; + + System.out.println("downloading " + MINIO_BINARY + " binary"); + + Request request = new Request.Builder().url(HttpUrl.parse(url)).method("GET", null).build(); + try (Response response = newHttpClient().newCall(request).execute()) { + if (!response.isSuccessful()) { + System.out.println("failed to download binary " + MINIO_BINARY); + return false; + } + + BufferedSink bufferedSink = Okio.buffer(Okio.sink(new File(MINIO_BINARY))); + bufferedSink.writeAll(response.body().source()); + bufferedSink.flush(); + bufferedSink.close(); + } + + if (!OS.contains("windows")) file.setExecutable(true); + + return true; + } + + public static Process runMinioServer(boolean tls) throws Exception { + File binaryPath = new File(new File(System.getProperty("user.dir")), MINIO_BINARY); + ProcessBuilder pb; + if (tls) { + pb = + new ProcessBuilder( + binaryPath.getPath(), + "server", + "--address", + ":9001", + "--certs-dir", + ".cfg/certs", + ".d{1...4}"); + } else { + pb = new ProcessBuilder(binaryPath.getPath(), "server", ".d{1...4}"); + } + + Map env = pb.environment(); + env.put("MINIO_ROOT_USER", "minio"); + env.put("MINIO_ROOT_PASSWORD", "minio123"); + env.put("MINIO_CI_CD", "1"); + // echo -n abcdefghijklmnopqrstuvwxyzABCDEF | base64 - + env.put("MINIO_KMS_SECRET_KEY", "my-minio-key:YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUY="); + env.put("MINIO_NOTIFY_WEBHOOK_ENABLE_miniojavatest", "on"); + env.put("MINIO_NOTIFY_WEBHOOK_ENDPOINT_miniojavatest", "http://example.org/"); + + pb.redirectErrorStream(true); + pb.redirectOutput(ProcessBuilder.Redirect.to(new File(MINIO_BINARY + ".log"))); + + if (tls) { + System.out.println("starting minio server in TLS"); + } else { + System.out.println("starting minio server"); + } + Process p = pb.start(); + Thread.sleep(10 * 1000); // wait for 10 seconds to do real start. + return p; + } +} diff --git a/functional/TestMinioAdminClient.java b/functional/TestMinioAdminClient.java index e7911dec6..e59e90403 100644 --- a/functional/TestMinioAdminClient.java +++ b/functional/TestMinioAdminClient.java @@ -15,144 +15,129 @@ * limitations under the License. */ -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.minio.admin.*; +import io.minio.admin.MinioAdminClient; +import io.minio.admin.Status; +import io.minio.admin.UserInfo; import java.util.Map; import org.junit.Assert; -@SuppressFBWarnings( +@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value = "REC", justification = "Allow catching super class Exception since it's tests") -public class TestMinioAdminClient { - - private final MinioAdminClient adminClient; - private final boolean mintEnv; - - private static String userAccessKey = FunctionalTest.getRandomName(); - private static String userSecretKey = FunctionalTest.getRandomName(); - private static String policyName = FunctionalTest.getRandomName(); - - public TestMinioAdminClient(MinioAdminClient adminClient, boolean mintEnv) { - this.adminClient = adminClient; - this.mintEnv = mintEnv; +public class TestMinioAdminClient extends TestArgs { + private MinioAdminClient client; + private static String userAccessKey = getRandomName(); + private static String userSecretKey = getRandomName(); + private static String policyName = getRandomName(); + + public TestMinioAdminClient(TestArgs args, MinioAdminClient client) { + super(args); + this.client = client; } public void addUser() throws Exception { String methodName = "addUser()"; - if (!mintEnv) { - System.out.println(methodName); - } + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - adminClient.addUser(userAccessKey, UserInfo.Status.ENABLED, userSecretKey, null, null); + client.addUser(userAccessKey, Status.ENABLED, userSecretKey, null, null); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void addCannedPolicy() throws Exception { String methodName = "addCannedPolicy()"; - if (!mintEnv) { - System.out.println(methodName); - } + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { String policyJson = "{'Version': '2012-10-17','Statement': [{'Action': ['s3:GetObject'],'Effect':" + " 'Allow','Resource': ['arn:aws:s3:::my-bucketname/*'],'Sid': ''}]}"; - adminClient.addCannedPolicy(policyName, policyJson.replaceAll("'", "\"")); + client.addCannedPolicy(policyName, policyJson.replaceAll("'", "\"")); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void listCannedPolicies() throws Exception { String methodName = "listCannedPolicies()"; - if (!mintEnv) { - System.out.println(methodName); - } - + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - Map policies = adminClient.listCannedPolicies(); + Map policies = client.listCannedPolicies(); String policy = policies.get(policyName); Assert.assertTrue(policy != null); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void removeCannedPolicy() throws Exception { String methodName = "removeCannedPolicy()"; - if (!mintEnv) { - System.out.println(methodName); - } + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - adminClient.removeCannedPolicy(policyName); + client.removeCannedPolicy(policyName); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void setPolicy() throws Exception { String methodName = "setPolicy()"; - if (!mintEnv) { - System.out.println(methodName); - } - + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - adminClient.setPolicy(userAccessKey, false, policyName); + client.setPolicy(userAccessKey, false, policyName); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void getUserInfo() throws Exception { String methodName = "getUserInfo()"; - if (!mintEnv) { - System.out.println(methodName); - } - + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - UserInfo userInfo = adminClient.getUserInfo(userAccessKey); - Assert.assertEquals(userInfo.status(), UserInfo.Status.ENABLED); + UserInfo userInfo = client.getUserInfo(userAccessKey); + Assert.assertEquals(userInfo.status(), Status.ENABLED); Assert.assertEquals(userInfo.policyName(), policyName); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void listUsers() throws Exception { String methodName = "listUsers()"; - if (!mintEnv) { - System.out.println(methodName); - } - + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - Map users = adminClient.listUsers(); + Map users = client.listUsers(); Assert.assertTrue(users.containsKey(userAccessKey)); - Assert.assertEquals(users.get(userAccessKey).status(), UserInfo.Status.ENABLED); + Assert.assertEquals(users.get(userAccessKey).status(), Status.ENABLED); Assert.assertEquals(users.get(userAccessKey).policyName(), policyName); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } public void deleteUser() throws Exception { String methodName = "deleteUser()"; - if (!mintEnv) { - System.out.println(methodName); - } - + if (!MINT_ENV) System.out.println(methodName); long startTime = System.currentTimeMillis(); + try { - adminClient.deleteUser(userAccessKey); + client.deleteUser(userAccessKey); } catch (Exception e) { - FunctionalTest.handleException(methodName, null, startTime, e); + handleException(methodName, null, startTime, e); } } diff --git a/functional/TestMinioClient.java b/functional/TestMinioClient.java new file mode 100644 index 000000000..9980bbbc3 --- /dev/null +++ b/functional/TestMinioClient.java @@ -0,0 +1,3553 @@ +/* + * MinIO Java SDK for Amazon S3 Compatible Cloud Storage, + * (C) 2015-2021 MinIO, 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. + */ + +import io.minio.BucketExistsArgs; +import io.minio.CloseableIterator; +import io.minio.ComposeObjectArgs; +import io.minio.CopyObjectArgs; +import io.minio.DeleteBucketCorsArgs; +import io.minio.DeleteBucketEncryptionArgs; +import io.minio.DeleteBucketLifecycleArgs; +import io.minio.DeleteBucketNotificationArgs; +import io.minio.DeleteBucketPolicyArgs; +import io.minio.DeleteBucketReplicationArgs; +import io.minio.DeleteBucketTagsArgs; +import io.minio.DeleteObjectLockConfigurationArgs; +import io.minio.DeleteObjectTagsArgs; +import io.minio.Directive; +import io.minio.DisableObjectLegalHoldArgs; +import io.minio.DownloadObjectArgs; +import io.minio.EnableObjectLegalHoldArgs; +import io.minio.GetBucketCorsArgs; +import io.minio.GetBucketEncryptionArgs; +import io.minio.GetBucketLifecycleArgs; +import io.minio.GetBucketNotificationArgs; +import io.minio.GetBucketPolicyArgs; +import io.minio.GetBucketReplicationArgs; +import io.minio.GetBucketTagsArgs; +import io.minio.GetBucketVersioningArgs; +import io.minio.GetObjectAclArgs; +import io.minio.GetObjectArgs; +import io.minio.GetObjectAttributesArgs; +import io.minio.GetObjectAttributesResponse; +import io.minio.GetObjectLockConfigurationArgs; +import io.minio.GetObjectRetentionArgs; +import io.minio.GetObjectTagsArgs; +import io.minio.GetPresignedObjectUrlArgs; +import io.minio.HeadObjectResponse; +import io.minio.Http; +import io.minio.IsObjectLegalHoldEnabledArgs; +import io.minio.ListBucketsArgs; +import io.minio.ListObjectsArgs; +import io.minio.ListenBucketNotificationArgs; +import io.minio.MakeBucketArgs; +import io.minio.MinioClient; +import io.minio.ObjectWriteResponse; +import io.minio.PostPolicy; +import io.minio.PutObjectArgs; +import io.minio.PutObjectFanOutArgs; +import io.minio.PutObjectFanOutEntry; +import io.minio.RemoveBucketArgs; +import io.minio.RemoveObjectArgs; +import io.minio.RemoveObjectsArgs; +import io.minio.Result; +import io.minio.SelectObjectContentArgs; +import io.minio.SelectResponseStream; +import io.minio.ServerSideEncryption; +import io.minio.SetBucketCorsArgs; +import io.minio.SetBucketEncryptionArgs; +import io.minio.SetBucketLifecycleArgs; +import io.minio.SetBucketNotificationArgs; +import io.minio.SetBucketPolicyArgs; +import io.minio.SetBucketReplicationArgs; +import io.minio.SetBucketTagsArgs; +import io.minio.SetBucketVersioningArgs; +import io.minio.SetObjectLockConfigurationArgs; +import io.minio.SetObjectRetentionArgs; +import io.minio.SetObjectTagsArgs; +import io.minio.SnowballObject; +import io.minio.SourceObject; +import io.minio.StatObjectArgs; +import io.minio.StatObjectResponse; +import io.minio.Time; +import io.minio.UploadObjectArgs; +import io.minio.UploadSnowballObjectsArgs; +import io.minio.Xml; +import io.minio.errors.ErrorResponseException; +import io.minio.messages.AccessControlList; +import io.minio.messages.AccessControlPolicy; +import io.minio.messages.CORSConfiguration; +import io.minio.messages.DeleteRequest; +import io.minio.messages.EventType; +import io.minio.messages.Filter; +import io.minio.messages.InputSerialization; +import io.minio.messages.LifecycleConfiguration; +import io.minio.messages.ListAllMyBucketsResult; +import io.minio.messages.NotificationConfiguration; +import io.minio.messages.NotificationRecords; +import io.minio.messages.ObjectLockConfiguration; +import io.minio.messages.OutputSerialization; +import io.minio.messages.ReplicationConfiguration; +import io.minio.messages.Retention; +import io.minio.messages.RetentionMode; +import io.minio.messages.SseAlgorithm; +import io.minio.messages.SseConfiguration; +import io.minio.messages.Stats; +import io.minio.messages.Status; +import io.minio.messages.Tags; +import io.minio.messages.VersioningConfiguration; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import okhttp3.Headers; +import okhttp3.MultipartBody; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.junit.Assert; + +@edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "REC", + justification = "Allow catching super class Exception since it's tests") +public class TestMinioClient extends TestArgs { + private String bucketName = getRandomName(); + private String bucketNameWithLock = getRandomName(); + public boolean isQuickTest; + private MinioClient client; + + public TestMinioClient(TestArgs args, boolean isQuickTest, MinioClient client) { + super(args); + this.isQuickTest = isQuickTest; + this.client = client; + } + + public void testBucketApi( + String methodName, + String testTags, + MakeBucketArgs args, + boolean existCheck, + boolean removeCheck) + throws Exception { + long startTime = System.currentTimeMillis(); + try { + client.makeBucket(args); + try { + Assert.assertFalse( + methodName + " failed after bucket creation", + existCheck + && !client.bucketExists( + BucketExistsArgs.builder() + .bucket(args.bucket()) + .region(args.region()) + .build())); + if (removeCheck) { + client.removeBucket( + RemoveBucketArgs.builder().bucket(args.bucket()).region(args.region()).build()); + } + mintSuccessLog(methodName, null, startTime); + } finally { + if (!removeCheck) { + client.removeBucket( + RemoveBucketArgs.builder().bucket(args.bucket()).region(args.region()).build()); + } + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testBucketApiCases(String methodName, boolean existCheck, boolean removeCheck) + throws Exception { + testBucketApi( + methodName, + "[basic check]", + MakeBucketArgs.builder().bucket(getRandomName()).build(), + existCheck, + removeCheck); + + if (isQuickTest) return; + + testBucketApi( + methodName, + "[object lock]", + MakeBucketArgs.builder().bucket(getRandomName()).objectLock(true).build(), + existCheck, + removeCheck); + testBucketApi( + methodName, + "[name contains period]", + MakeBucketArgs.builder().bucket(getRandomName() + ".withperiod").build(), + existCheck, + removeCheck); + } + + public void makeBucket() throws Exception { + String methodName = "makeBucket()"; + if (!MINT_ENV) System.out.println(methodName); + + testBucketApiCases(methodName, false, false); + + if (isQuickTest) return; + + if (!endpoint.contains(".amazonaws.com")) { + mintIgnoredLog(methodName, "[region]", System.currentTimeMillis()); + mintIgnoredLog(methodName, "[region, object lock]", System.currentTimeMillis()); + return; + } + + testBucketApi( + methodName, + "[region]", + MakeBucketArgs.builder().bucket(getRandomName()).region("eu-west-1").build(), + false, + false); + testBucketApi( + methodName, + "[region, object lock]", + MakeBucketArgs.builder() + .bucket(getRandomName()) + .region("eu-central-1") + .objectLock(true) + .build(), + false, + false); + } + + public void listBuckets() throws Exception { + String methodName = "listBuckets()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + List expectedBucketNames = new LinkedList<>(); + try { + try { + String bucketName = getRandomName(); + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + expectedBucketNames.add(bucketName); + + bucketName = getRandomName(); + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); + expectedBucketNames.add(bucketName); + + bucketName = getRandomName() + ".withperiod"; + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + expectedBucketNames.add(bucketName); + + List bucketNames = new LinkedList<>(); + for (Result result : + client.listBuckets(ListBucketsArgs.builder().maxBuckets(1).build())) { + ListAllMyBucketsResult.Bucket bucket = result.get(); + if (expectedBucketNames.contains(bucket.name())) bucketNames.add(bucket.name()); + } + + Assert.assertTrue( + "bucket names differ; expected = " + expectedBucketNames + ", got = " + bucketNames, + expectedBucketNames.containsAll(bucketNames)); + + mintSuccessLog(methodName, null, startTime); + } finally { + for (String bucketName : expectedBucketNames) { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void bucketExists() throws Exception { + String methodName = "bucketExists()"; + if (!MINT_ENV) System.out.println(methodName); + + testBucketApiCases(methodName, true, false); + } + + public void removeBucket() throws Exception { + String methodName = "removeBucket()"; + if (!MINT_ENV) System.out.println(methodName); + + testBucketApiCases(methodName, false, true); + } + + public void setBucketVersioning() throws Exception { + String methodName = "setBucketVersioning()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String name = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(name).build()); + try { + client.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket(name) + .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) + .build()); + client.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket(name) + .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)) + .build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(name).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketVersioning() throws Exception { + String methodName = "getBucketVersioning()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String name = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(name).build()); + try { + VersioningConfiguration config = + client.getBucketVersioning(GetBucketVersioningArgs.builder().bucket(name).build()); + Assert.assertEquals( + "getBucketVersioning(); expected = \"\", got = " + config.status(), + config.status(), + VersioningConfiguration.Status.OFF); + client.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket(name) + .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) + .build()); + config = client.getBucketVersioning(GetBucketVersioningArgs.builder().bucket(name).build()); + Assert.assertEquals( + "getBucketVersioning(); expected = " + + VersioningConfiguration.Status.ENABLED + + ", got = " + + config.status(), + config.status(), + VersioningConfiguration.Status.ENABLED); + + client.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket(name) + .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null)) + .build()); + config = client.getBucketVersioning(GetBucketVersioningArgs.builder().bucket(name).build()); + Assert.assertEquals( + "getBucketVersioning(); expected = " + + VersioningConfiguration.Status.SUSPENDED + + ", got = " + + config.status(), + config.status(), + VersioningConfiguration.Status.SUSPENDED); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(name).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setup() throws Exception { + long startTime = System.currentTimeMillis(); + + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + } catch (Exception e) { + handleException("makeBucket()", null, startTime, e); + } + + try { + client.makeBucket( + MakeBucketArgs.builder().bucket(bucketNameWithLock).objectLock(true).build()); + } catch (Exception e) { + if (e instanceof ErrorResponseException) { + if (((ErrorResponseException) e).errorResponse().code().equals("NotImplemented")) { + bucketNameWithLock = null; + return; + } + } + + handleException("makeBucket()", "[object lock]", startTime, e); + } + } + + public void teardown() throws Exception { + long startTime = System.currentTimeMillis(); + try { + if (bucketName != null) { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + + if (bucketNameWithLock != null) { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketNameWithLock).build()); + } + } catch (Exception e) { + handleException("removeBucket()", null, startTime, e); + } + } + + public void testUploadObject(String testTags, String filename, String contentType) + throws Exception { + String methodName = "uploadObject()"; + long startTime = System.currentTimeMillis(); + try { + try { + UploadObjectArgs.Builder builder = + UploadObjectArgs.builder().bucket(bucketName).object(filename).filename(filename); + if (contentType != null) builder.contentType(contentType); + client.uploadObject(builder.build()); + mintSuccessLog(methodName, testTags, startTime); + } finally { + Files.delete(Paths.get(filename)); + client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(filename).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void uploadObject() throws Exception { + String methodName = "uploadObject()"; + if (!MINT_ENV) System.out.println(methodName); + + testUploadObject("[single upload]", createFile1Kb(), null); + + if (isQuickTest) return; + + testUploadObject("[multi-part upload]", createFile6Mb(), null); + testUploadObject("[custom content-type]", createFile1Kb(), CUSTOM_CONTENT_TYPE); + } + + public void testPutObject(String testTags, PutObjectArgs args, String errorCode) + throws Exception { + String methodName = "putObject()"; + long startTime = System.currentTimeMillis(); + try { + ObjectWriteResponse objectInfo = null; + try { + objectInfo = client.putObject(args); + } catch (ErrorResponseException e) { + if (errorCode == null || !e.errorResponse().code().equals(errorCode)) throw e; + } + if (args.retention() != null) { + client.setObjectRetention( + SetObjectRetentionArgs.builder() + .bucket(args.bucket()) + .object(args.object()) + .config(new Retention()) + .bypassGovernanceMode(true) + .build()); + } + client.removeObject( + RemoveObjectArgs.builder() + .bucket(args.bucket()) + .object(args.object()) + .versionId(objectInfo != null ? objectInfo.versionId() : null) + .build()); + + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testThreadedPutObject() throws Exception { + String methodName = "putObject()"; + String testTags = "[threaded]"; + long startTime = System.currentTimeMillis(); + try { + int count = 7; + Thread[] threads = new Thread[count]; + + for (int i = 0; i < count; i++) { + threads[i] = new Thread(new PutObjectRunnable(client, bucketName, createFile6Mb())); + } + + for (int i = 0; i < count; i++) threads[i].start(); + + // Waiting for threads to complete. + for (int i = 0; i < count; i++) threads[i].join(); + + // All threads are completed. + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void putObject() throws Exception { + String methodName = "putObject()"; + if (!MINT_ENV) System.out.println(methodName); + + testPutObject( + "[single upload]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .build(), + null); + + if (isQuickTest) return; + + testPutObject( + "[multi-part upload]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(11 * MB), 11L * MB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .build(), + null); + + testPutObject( + "[object name with path segments]", + PutObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .build(), + null); + + testPutObject( + "[zero sized object]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(0), 0L, null) + .build(), + null); + + testPutObject( + "[object name ends with '/']", + PutObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName() + "/") + .stream(new ContentInputStream(0), 0L, null) + .contentType(CUSTOM_CONTENT_TYPE) + .build(), + null); + + testPutObject( + "[unknown stream size, single upload]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), null, (long) PutObjectArgs.MIN_MULTIPART_SIZE) + .contentType(CUSTOM_CONTENT_TYPE) + .build(), + null); + + testPutObject( + "[unknown stream size, multi-part upload]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(11 * MB), null, (long) PutObjectArgs.MIN_MULTIPART_SIZE) + .contentType(CUSTOM_CONTENT_TYPE) + .build(), + null); + + Map userMetadata = new HashMap<>(); + userMetadata.put("My-Project", "Project One"); + userMetadata.put("My-header1", " a b c "); + userMetadata.put("My-Header2", "\"a b c\""); + userMetadata.put("My-Unicode-Tag", "商品"); + + testPutObject( + "[user metadata]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .userMetadata(userMetadata) + .build(), + null); + + Map headers = new HashMap<>(); + + headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); + testPutObject( + "[storage-class=REDUCED_REDUNDANCY]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .headers(headers) + .build(), + null); + + headers.put("X-Amz-Storage-Class", "STANDARD"); + testPutObject( + "[storage-class=STANDARD]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .headers(headers) + .build(), + null); + + headers.put("X-Amz-Storage-Class", "INVALID"); + testPutObject( + "[storage-class=INVALID negative case]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .headers(headers) + .build(), + "InvalidStorageClass"); + + testPutObject( + "[SSE-S3]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .sse(SSE_S3) + .build(), + null); + + if (bucketNameWithLock != null) { + testPutObject( + "[with retention]", + PutObjectArgs.builder().bucket(bucketNameWithLock).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .retention( + new Retention(RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(1))) + .build(), + null); + } + + testThreadedPutObject(); + + if (!isSecureEndpoint) return; + + testPutObject( + "[SSE-C single upload]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .sse(SSE_C) + .build(), + null); + + testPutObject( + "[SSE-C multi-part upload]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(11 * MB), 11L * MB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .sse(SSE_C) + .build(), + null); + + if (sseKms == null) { + mintIgnoredLog(methodName, null, System.currentTimeMillis()); + return; + } + + testPutObject( + "[SSE-KMS]", + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .contentType(CUSTOM_CONTENT_TYPE) + .sse(sseKms) + .build(), + null); + } + + public void testStatObject(String testTags, PutObjectArgs args, StatObjectResponse expectedStat) + throws Exception { + String methodName = "statObject()"; + long startTime = System.currentTimeMillis(); + try { + client.putObject(args); + try { + ServerSideEncryption.CustomerKey ssec = null; + if (args.sse() instanceof ServerSideEncryption.CustomerKey) { + ssec = (ServerSideEncryption.CustomerKey) args.sse(); + } + StatObjectResponse stat = + client.statObject( + StatObjectArgs.builder() + .bucket(args.bucket()) + .object(args.object()) + .ssec(ssec) + .build()); + + Assert.assertEquals( + "bucket name: expected = " + expectedStat.bucket() + ", got = " + stat.bucket(), + expectedStat.bucket(), + stat.bucket()); + + Assert.assertEquals( + "object name: expected = " + expectedStat.object() + ", got = " + stat.object(), + expectedStat.object(), + stat.object()); + + Assert.assertEquals( + "length: expected = " + expectedStat.size() + ", got = " + stat.size(), + expectedStat.size(), + stat.size()); + + Assert.assertEquals( + "content-type: expected = " + + expectedStat.contentType() + + ", got = " + + stat.contentType(), + expectedStat.contentType(), + stat.contentType()); + + for (String key : expectedStat.userMetadata().keySet()) { + Assert.assertTrue("metadata " + key + " not found", stat.userMetadata().containsKey(key)); + Assert.assertEquals( + "metadata " + + key + + " value: expected: " + + expectedStat.userMetadata().get(key) + + ", got: " + + stat.userMetadata().get(key), + expectedStat.userMetadata().get(key), + stat.userMetadata().get(key)); + } + + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void statObject() throws Exception { + String methodName = "statObject()"; + if (!MINT_ENV) System.out.println(methodName); + + String objectName = getRandomName(); + + PutObjectArgs.Builder builder = + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1024), 1024L, null); + Headers.Builder headersBuilder = + new Headers.Builder() + .add("Content-Type: application/octet-stream") + .add("Content-Length: 1024") + .add("Last-Modified", ZonedDateTime.now().format(Time.HTTP_HEADER_DATE_FORMAT)); + + testStatObject( + "[basic check]", + builder.build(), + new StatObjectResponse( + new HeadObjectResponse(headersBuilder.build(), bucketName, null, objectName))); + + Map headers = new HashMap<>(); + headers.put("Content-Type", CUSTOM_CONTENT_TYPE); + Map userMetadata = new HashMap<>(); + userMetadata.put("My-Project", "Project One"); + builder = builder.headers(headers).userMetadata(userMetadata); + builder = builder.stream(new ContentInputStream(1024), 1024L, null); + + StatObjectResponse stat = + new StatObjectResponse( + new HeadObjectResponse( + headersBuilder + .set("Content-Type", CUSTOM_CONTENT_TYPE) + .add("X-Amz-Meta-My-Project: Project One") + .build(), + bucketName, + null, + objectName)); + + testStatObject("[user metadata]", builder.build(), stat); + + if (isQuickTest) return; + + builder = builder.stream(new ContentInputStream(1024), 1024L, null); + testStatObject("[SSE-S3]", builder.sse(SSE_S3).build(), stat); + + if (!isSecureEndpoint) { + mintIgnoredLog(methodName, "[SSE-C]", System.currentTimeMillis()); + return; + } + + builder = builder.stream(new ContentInputStream(1024), 1024L, null); + testStatObject("[SSE-C]", builder.sse(SSE_C).build(), stat); + + if (sseKms == null) { + mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); + return; + } + + builder = builder.stream(new ContentInputStream(1024), 1024L, null); + testStatObject("[SSE-KMS]", builder.sse(sseKms).build(), stat); + } + + public void testGetObject( + String testTags, + long objectSize, + ServerSideEncryption sse, + GetObjectArgs args, + int length, + String sha256sum) + throws Exception { + String methodName = "getObject()"; + long startTime = System.currentTimeMillis(); + try { + PutObjectArgs.Builder builder = + PutObjectArgs.builder().bucket(args.bucket()).object(args.object()).stream( + new ContentInputStream(objectSize), objectSize, null); + if (sse != null) builder.sse(sse); + client.putObject(builder.build()); + + try (InputStream is = client.getObject(args)) { + String checksum = getSha256Sum(is, length); + Assert.assertEquals( + "checksum mismatch. expected: " + sha256sum + ", got: " + checksum, + checksum, + sha256sum); + } + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + } + } + + public void getObject() throws Exception { + String methodName = "getObject()"; + if (!MINT_ENV) System.out.println(methodName); + + testGetObject( + "[single upload]", + 1 * KB, + null, + GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).build(), + 1 * KB, + getSha256Sum(new ContentInputStream(1 * KB), 1 * KB)); + + if (isQuickTest) return; + + InputStream cis = new ContentInputStream(1 * KB); + skipStream(cis, 1000); + testGetObject( + "[single upload, offset]", + 1 * KB, + null, + GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).offset(1000L).build(), + 1 * KB - 1000, + getSha256Sum(cis, 1 * KB - 1000)); + + testGetObject( + "[single upload, length]", + 1 * KB, + null, + GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).length(256L).build(), + 256, + getSha256Sum(new ContentInputStream(1 * KB), 256)); + + cis = new ContentInputStream(1 * KB); + skipStream(cis, 1000); + testGetObject( + "[single upload, offset, length]", + 1 * KB, + null, + GetObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .offset(1000L) + .length(24L) + .build(), + 24, + getSha256Sum(cis, 24)); + + cis = new ContentInputStream(1 * KB); + skipStream(cis, 1000); + testGetObject( + "[single upload, offset, length beyond available]", + 1 * KB, + null, + GetObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .offset(1000L) + .length(30L) + .build(), + 24, + getSha256Sum(cis, 24)); + + testGetObject( + "[multi-part upload]", + 6 * MB, + null, + GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).build(), + 6 * MB, + getSha256Sum(new ContentInputStream(6 * MB), 6 * MB)); + + cis = new ContentInputStream(6 * MB); + skipStream(cis, 1000); + testGetObject( + "[multi-part upload, offset, length]", + 6 * MB, + null, + GetObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .offset(1000L) + .length(64 * 1024L) + .build(), + 64 * KB, + getSha256Sum(cis, 64 * 1024)); + + cis = new ContentInputStream(0); + testGetObject( + "[zero sized object]", + 0, + null, + GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).build(), + 0, + getSha256Sum(cis, 0)); + + if (!isSecureEndpoint) return; + + testGetObject( + "[single upload, SSE-C]", + 1 * KB, + SSE_C, + GetObjectArgs.builder().bucket(bucketName).object(getRandomName()).ssec(SSE_C).build(), + 1 * KB, + getSha256Sum(new ContentInputStream(1 * KB), 1 * KB)); + } + + public void testDownloadObject( + String testTags, int objectSize, ServerSideEncryption sse, DownloadObjectArgs args) + throws Exception { + String methodName = "downloadObject()"; + long startTime = System.currentTimeMillis(); + try { + PutObjectArgs.Builder builder = + PutObjectArgs.builder().bucket(args.bucket()).object(args.object()).stream( + new ContentInputStream(objectSize), (long) objectSize, null); + if (sse != null) builder.sse(sse); + client.putObject(builder.build()); + client.downloadObject(args); + Files.delete(Paths.get(args.filename())); + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + } + } + + public void downloadObject() throws Exception { + String methodName = "downloadObject()"; + if (!MINT_ENV) System.out.println(methodName); + + String objectName = getRandomName(); + testDownloadObject( + "[single upload]", + 1 * KB, + null, + DownloadObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .filename(objectName + ".downloaded") + .build()); + + if (isQuickTest) return; + + String baseName = getRandomName(); + objectName = "path/to/" + baseName; + testDownloadObject( + "[single upload with multiple path segments]", + 1 * KB, + null, + DownloadObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .filename(baseName + ".downloaded") + .build()); + + if (!isSecureEndpoint) return; + + objectName = getRandomName(); + testDownloadObject( + "[single upload, SSE-C]", + 1 * KB, + SSE_C, + DownloadObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .ssec(SSE_C) + .filename(objectName + ".downloaded") + .build()); + } + + public List createObjects(String bucketName, int count, int versions) + throws Exception { + List results = new LinkedList<>(); + for (int i = 0; i < count; i++) { + String objectName = getRandomName(); + results.add( + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1), 1L, null) + .build())); + if (versions > 1) { + for (int j = 0; j < versions - 1; j++) { + results.add( + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1), 1L, null) + .build())); + } + } + } + + return results; + } + + public void removeObjects(String bucketName, List results) throws Exception { + List objects = + results.stream() + .map( + result -> { + return new DeleteRequest.Object(result.object(), result.versionId()); + }) + .collect(Collectors.toList()); + for (Result r : + client.removeObjects( + RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build())) { + ignore(r.get()); + } + } + + public void testListObjects(String testTags, ListObjectsArgs args, int objCount, int versions) + throws Exception { + String methodName = "listObjects()"; + long startTime = System.currentTimeMillis(); + String bucketName = args.bucket(); + List results = null; + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + if (versions > 0) { + client.setBucketVersioning( + SetBucketVersioningArgs.builder() + .bucket(bucketName) + .config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null)) + .build()); + } + + results = createObjects(bucketName, objCount, versions); + + int i = 0; + for (Result r : client.listObjects(args)) { + r.get(); + i++; + } + + if (versions > 0) objCount *= versions; + + Assert.assertEquals("object count; expected=" + objCount + ", got=" + i, i, objCount); + mintSuccessLog(methodName, testTags, startTime); + } finally { + if (results != null) removeObjects(bucketName, results); + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void listObjects() throws Exception { + if (!MINT_ENV) System.out.println("listObjects()"); + + testListObjects("[bucket]", ListObjectsArgs.builder().bucket(getRandomName()).build(), 3, 0); + + testListObjects( + "[bucket, prefix]", + ListObjectsArgs.builder().bucket(getRandomName()).prefix("minio").build(), + 3, + 0); + + testListObjects( + "[bucket, prefix, recursive]", + ListObjectsArgs.builder().bucket(getRandomName()).prefix("minio").recursive(true).build(), + 3, + 0); + + testListObjects( + "[bucket, versions]", + ListObjectsArgs.builder().bucket(getRandomName()).includeVersions(true).build(), + 3, + 2); + + if (isQuickTest) return; + + testListObjects( + "[empty bucket]", ListObjectsArgs.builder().bucket(getRandomName()).build(), 0, 0); + + testListObjects( + "[bucket, prefix, recursive, 1050 objects]", + ListObjectsArgs.builder().bucket(getRandomName()).prefix("minio").recursive(true).build(), + 1050, + 0); + + testListObjects( + "[bucket, apiVersion1]", + ListObjectsArgs.builder().bucket(getRandomName()).useApiVersion1(true).build(), + 3, + 0); + } + + public void testRemoveObject(String testTags, ServerSideEncryption sse, RemoveObjectArgs args) + throws Exception { + String methodName = "removeObject()"; + long startTime = System.currentTimeMillis(); + try { + PutObjectArgs.Builder builder = + PutObjectArgs.builder().bucket(args.bucket()).object(args.object()).stream( + new ContentInputStream(1), 1L, null); + if (sse != null) builder.sse(sse); + client.putObject(builder.build()); + client.removeObject(args); + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void removeObject() throws Exception { + String methodName = "removeObject()"; + if (!MINT_ENV) System.out.println(methodName); + + testRemoveObject( + "[base check]", + null, + RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); + testRemoveObject( + "[multiple path segments]", + null, + RemoveObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName()).build()); + + if (isQuickTest) return; + + testRemoveObject( + "[SSE-S3]", + SSE_S3, + RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); + + if (!isSecureEndpoint) { + mintIgnoredLog(methodName, "[SSE-C]", System.currentTimeMillis()); + mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); + return; + } + + testRemoveObject( + "[SSE-C]", + SSE_C, + RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); + + if (sseKms == null) { + mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); + return; + } + + testRemoveObject( + "[SSE-KMS]", + sseKms, + RemoveObjectArgs.builder().bucket(bucketName).object(getRandomName()).build()); + } + + public void testRemoveObjects(String testTags, List results) + throws Exception { + String methodName = "removeObjects()"; + long startTime = System.currentTimeMillis(); + try { + removeObjects(bucketName, results); + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } finally { + removeObjects(bucketName, results); + } + } + + public void removeObjects() throws Exception { + String methodName = "removeObjects()"; + if (!MINT_ENV) System.out.println(methodName); + + testRemoveObjects("[basic]", createObjects(bucketName, 3, 0)); + + String testTags = "[3005 objects]"; + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + List results = new LinkedList<>(); + for (int i = 0; i < 3004; i++) { + results.add( + new ObjectWriteResponse(null, bucketName, null, objectName + "-" + i, null, null)); + } + List existingObject = createObjects(bucketName, 1, 0); + results.addAll(existingObject); + testRemoveObjects(testTags, results); + try { + client.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(existingObject.get(0).object()) + .build()); + handleException( + methodName, + testTags, + startTime, + new Exception("object " + existingObject.get(0).object() + " still exist")); + } catch (ErrorResponseException e) { + if (!e.errorResponse().code().equals("NoSuchKey")) throw e; + } + } + + public void testGetPresignedUrl(GetPresignedObjectUrlArgs args, String expectedChecksum) + throws Exception { + String urlString = client.getPresignedObjectUrl(args); + byte[] data = readObject(urlString); + String checksum = getSha256Sum(new ByteArrayInputStream(data), data.length); + Assert.assertEquals( + "content checksum differs; expected = " + expectedChecksum + ", got = " + checksum, + expectedChecksum, + checksum); + } + + public void testGetPresignedObjectUrlForGet() throws Exception { + String methodName = "getPresignedObjectUrl()"; + String testTags = null; + long startTime = System.currentTimeMillis(); + try { + String expectedChecksum = getSha256Sum(new ContentInputStream(1 * KB), 1 * KB); + String objectName = getRandomName(); + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + try { + testTags = "[GET]"; + testGetPresignedUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.GET) + .bucket(bucketName) + .object(objectName) + .build(), + expectedChecksum); + + testTags = "[GET, expiry]"; + testGetPresignedUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.GET) + .bucket(bucketName) + .object(objectName) + .expiry(1, TimeUnit.DAYS) + .build(), + expectedChecksum); + + testTags = "[GET, expiry, query params]"; + Map queryParams = new HashMap<>(); + queryParams.put("response-content-type", "application/json"); + testGetPresignedUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.GET) + .bucket(bucketName) + .object(objectName) + .expiry(1, TimeUnit.DAYS) + .extraQueryParams(queryParams) + .build(), + expectedChecksum); + + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testPutPresignedUrl( + String testTags, byte[] data, String expectedChecksum, GetPresignedObjectUrlArgs args) + throws Exception { + String methodName = "getPresignedObjectUrl()"; + long startTime = System.currentTimeMillis(); + try { + String urlString = client.getPresignedObjectUrl(args); + try { + writeObject(urlString, data); + InputStream is = + client.getObject( + GetObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + data = readAllBytes(is); + String checksum = getSha256Sum(new ByteArrayInputStream(data), data.length); + Assert.assertEquals( + "content checksum differs; expected = " + expectedChecksum + ", got = " + checksum, + expectedChecksum, + checksum); + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testGetPresignedObjectUrlForPut() throws Exception { + byte[] data = "hello, world".getBytes(StandardCharsets.UTF_8); + String expectedChecksum = getSha256Sum(new ByteArrayInputStream(data), data.length); + String objectName = getRandomName(); + + testPutPresignedUrl( + "[PUT]", + data, + expectedChecksum, + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.PUT) + .bucket(bucketName) + .object(objectName) + .build()); + + testPutPresignedUrl( + "[PUT, expiry]", + data, + expectedChecksum, + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.PUT) + .bucket(bucketName) + .object(objectName) + .expiry(1, TimeUnit.DAYS) + .build()); + } + + public void getPresignedObjectUrl() throws Exception { + if (!MINT_ENV) System.out.println("getPresignedObjectUrl()"); + + testGetPresignedObjectUrlForGet(); + testGetPresignedObjectUrlForPut(); + } + + public void getPresignedPostFormData() throws Exception { + String methodName = "getPresignedPostFormData()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + try { + String objectName = getRandomName(); + + PostPolicy policy = new PostPolicy(bucketName, ZonedDateTime.now().plusDays(7)); + policy.addEqualsCondition("key", objectName); + policy.addEqualsCondition("content-type", "image/png"); + policy.addContentLengthRangeCondition(1 * MB, 4 * MB); + Map formData = client.getPresignedPostFormData(policy); + + MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); + multipartBuilder.setType(MultipartBody.FORM); + for (Map.Entry entry : formData.entrySet()) { + multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue()); + } + multipartBuilder.addFormDataPart("key", objectName); + multipartBuilder.addFormDataPart("Content-Type", "image/png"); + multipartBuilder.addFormDataPart( + "file", + objectName, + RequestBody.create(readAllBytes(new ContentInputStream(1 * MB)), null)); + + String urlString = + client.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Http.Method.GET) + .bucket(bucketName) + .object("x") + .build()); + urlString = urlString.split("\\?")[0]; // Remove query parameters. + // remove last two characters to get clean url string of bucket. + urlString = urlString.substring(0, urlString.length() - 2); + Request request = new Request.Builder().url(urlString).post(multipartBuilder.build()).build(); + try (Response response = newHttpClient().newCall(request).execute()) { + Assert.assertNotNull("no response from server", response); + if (!response.isSuccessful()) { + String errorXml = response.body().string(); + throw new Exception( + "failed to upload object. Response: " + response + ", Error: " + errorXml); + } + } + client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void testCopyObject( + String testTags, ServerSideEncryption sse, CopyObjectArgs args, boolean negativeCase) + throws Exception { + String methodName = "copyObject()"; + long startTime = System.currentTimeMillis(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(args.source().bucket()).build()); + try { + PutObjectArgs.Builder builder = + PutObjectArgs.builder().bucket(args.source().bucket()).object(args.source().object()) + .stream(new ContentInputStream(1 * KB), 1L * KB, null); + if (sse != null) builder.sse(sse); + client.putObject(builder.build()); + + if (negativeCase) { + try { + client.copyObject(args); + } catch (ErrorResponseException e) { + if (!e.errorResponse().code().equals("PreconditionFailed")) { + throw e; + } + } + } else { + client.copyObject(args); + + ServerSideEncryption.CustomerKey ssec = null; + if (sse instanceof ServerSideEncryption.CustomerKey) { + ssec = (ServerSideEncryption.CustomerKey) sse; + } + client.statObject( + StatObjectArgs.builder() + .bucket(args.bucket()) + .object(args.object()) + .ssec(ssec) + .build()); + } + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder() + .bucket(args.source().bucket()) + .object(args.source().object()) + .build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(args.source().bucket()).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testCopyObjectMatchETag() throws Exception { + String methodName = "copyObject()"; + String testTags = "[match etag]"; + long startTime = System.currentTimeMillis(); + String srcBucketName = getRandomName(); + String srcObjectName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); + try { + ObjectWriteResponse result = + client.putObject( + PutObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + client.copyObject( + CopyObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .source( + SourceObject.builder() + .bucket(srcBucketName) + .object(srcObjectName) + .matchETag(result.etag()) + .build()) + .build()); + + client.statObject( + StatObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testCopyObjectMetadataReplace() throws Exception { + String methodName = "copyObject()"; + String testTags = "[metadata replace]"; + long startTime = System.currentTimeMillis(); + String srcBucketName = getRandomName(); + String srcObjectName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); + try { + client.putObject( + PutObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + Map headers = new HashMap<>(); + headers.put("Content-Type", CUSTOM_CONTENT_TYPE); + headers.put("X-Amz-Meta-My-Project", "Project One"); + client.copyObject( + CopyObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .source(SourceObject.builder().bucket(srcBucketName).object(srcObjectName).build()) + .headers(headers) + .metadataDirective(Directive.REPLACE) + .build()); + + StatObjectResponse stat = + client.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .build()); + Assert.assertEquals( + "content type differs. expected: " + + CUSTOM_CONTENT_TYPE + + ", got: " + + stat.contentType(), + CUSTOM_CONTENT_TYPE, + stat.contentType()); + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testCopyObjectEmptyMetadataReplace() throws Exception { + String methodName = "copyObject()"; + String testTags = "[empty metadata replace]"; + long startTime = System.currentTimeMillis(); + String srcBucketName = getRandomName(); + String srcObjectName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); + try { + Map headers = new HashMap<>(); + headers.put("Content-Type", CUSTOM_CONTENT_TYPE); + headers.put("X-Amz-Meta-My-Project", "Project One"); + client.putObject( + PutObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .headers(headers) + .build()); + + client.copyObject( + CopyObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .source(SourceObject.builder().bucket(srcBucketName).object(srcObjectName).build()) + .metadataDirective(Directive.REPLACE) + .build()); + + StatObjectResponse stat = + client.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .build()); + Assert.assertFalse( + "expected user metadata to be removed in new object", + stat.userMetadata().containsKey("My-Project")); + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void copyObject() throws Exception { + String methodName = "copyObject()"; + if (!MINT_ENV) System.out.println(methodName); + + String objectName = getRandomName(); + testCopyObject( + "[basic check]", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .source(SourceObject.builder().bucket(getRandomName()).object(objectName).build()) + .build(), + false); + + if (isQuickTest) return; + + testCopyObject( + "[negative match etag]", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .source( + SourceObject.builder() + .bucket(getRandomName()) + .object(getRandomName()) + .matchETag("invalid-etag") + .build()) + .build(), + true); + + testCopyObjectMatchETag(); + + testCopyObject( + "[not match etag]", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .source( + SourceObject.builder() + .bucket(getRandomName()) + .object(getRandomName()) + .notMatchETag("not-etag-of-source-object") + .build()) + .build(), + false); + + testCopyObject( + "[modified since]", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .source( + SourceObject.builder() + .bucket(getRandomName()) + .object(getRandomName()) + .modifiedSince(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)) + .build()) + .build(), + false); + + testCopyObject( + "[negative unmodified since]", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .source( + SourceObject.builder() + .bucket(getRandomName()) + .object(getRandomName()) + .unmodifiedSince(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)) + .build()) + .build(), + true); + + testCopyObjectMetadataReplace(); + testCopyObjectEmptyMetadataReplace(); + + testCopyObject( + "[SSE-S3]", + SSE_S3, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(SSE_S3) + .source(SourceObject.builder().bucket(getRandomName()).object(getRandomName()).build()) + .build(), + false); + + if (!isSecureEndpoint) { + mintIgnoredLog(methodName, "[SSE-C]", System.currentTimeMillis()); + mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); + return; + } + + testCopyObject( + "[SSE-C]", + SSE_C, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(SSE_C) + .source( + SourceObject.builder() + .bucket(getRandomName()) + .object(getRandomName()) + .ssec(SSE_C) + .build()) + .build(), + false); + + if (sseKms == null) { + mintIgnoredLog(methodName, "[SSE-KMS]", System.currentTimeMillis()); + return; + } + + testCopyObject( + "[SSE-KMS]", + sseKms, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(sseKms) + .source(SourceObject.builder().bucket(getRandomName()).object(getRandomName()).build()) + .build(), + false); + } + + public void testComposeObject(String testTags, ComposeObjectArgs args) throws Exception { + String methodName = "composeObject()"; + long startTime = System.currentTimeMillis(); + try { + client.composeObject(args); + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public List createSourceObjectList(SourceObject... sources) { + return Arrays.asList(sources); + } + + public void composeObjectTests(String object1Mb, String object6Mb, String object6MbSsec) + throws Exception { + testComposeObject( + "[single source]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder().bucket(bucketName).object(object1Mb).build())) + .build()); + + testComposeObject( + "[single source with offset]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder() + .bucket(bucketName) + .object(object1Mb) + .offset(2L * KB) + .build())) + .build()); + + testComposeObject( + "[single source with offset and length]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder() + .bucket(bucketName) + .object(object1Mb) + .offset(2L * KB) + .length(5L * KB) + .build())) + .build()); + + testComposeObject( + "[single multipart source]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder().bucket(bucketName).object(object6Mb).build())) + .build()); + + testComposeObject( + "[two multipart source]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder().bucket(bucketName).object(object6Mb).build(), + SourceObject.builder().bucket(bucketName).object(object6Mb).build())) + .build()); + + testComposeObject( + "[two multipart sources with offset and length]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder() + .bucket(bucketName) + .object(object6Mb) + .offset(10L) + .length(6291436L) + .build(), + SourceObject.builder().bucket(bucketName).object(object6Mb).build())) + .build()); + + if (isQuickTest) return; + + if (!isSecureEndpoint) return; + + testComposeObject( + "[two SSE-C multipart sources]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(SSE_C) + .sources( + createSourceObjectList( + SourceObject.builder() + .bucket(bucketName) + .object(object6MbSsec) + .ssec(SSE_C) + .build(), + SourceObject.builder() + .bucket(bucketName) + .object(object6MbSsec) + .ssec(SSE_C) + .build())) + .build()); + + testComposeObject( + "[two multipart sources with one SSE-C]", + ComposeObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sources( + createSourceObjectList( + SourceObject.builder() + .bucket(bucketName) + .object(object6MbSsec) + .ssec(SSE_C) + .build(), + SourceObject.builder().bucket(bucketName).object(object6Mb).build())) + .build()); + } + + public void composeObject() throws Exception { + String methodName = "composeObject()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + List createdObjects = new LinkedList<>(); + + try { + String object1Mb = null; + String object6Mb = null; + String object6MbSsec = null; + try { + ObjectWriteResponse response; + response = + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(1 * MB), 1L * MB, null) + .build()); + createdObjects.add(response); + object1Mb = response.object(); + + response = + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(6 * MB), 6L * MB, null) + .build()); + createdObjects.add(response); + object6Mb = response.object(); + + if (isSecureEndpoint) { + response = + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(getRandomName()).stream( + new ContentInputStream(6 * MB), 6L * MB, null) + .sse(SSE_C) + .build()); + createdObjects.add(response); + object6MbSsec = response.object(); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + + composeObjectTests(object1Mb, object6Mb, object6MbSsec); + } finally { + removeObjects(bucketName, createdObjects); + } + } + + public void checkObjectLegalHold(String bucketName, String objectName, boolean enableCheck) + throws Exception { + if (enableCheck) { + client.enableObjectLegalHold( + EnableObjectLegalHoldArgs.builder().bucket(bucketName).object(objectName).build()); + } else { + client.disableObjectLegalHold( + DisableObjectLegalHoldArgs.builder().bucket(bucketName).object(objectName).build()); + } + + boolean result = + client.isObjectLegalHoldEnabled( + IsObjectLegalHoldEnabledArgs.builder().bucket(bucketName).object(objectName).build()); + Assert.assertEquals( + "object legal hold: expected: " + enableCheck + ", got: " + result, result, enableCheck); + } + + public void enableObjectLegalHold() throws Exception { + if (bucketNameWithLock == null) return; + + String methodName = "enableObjectLegalHold()"; + if (!MINT_ENV) System.out.println(methodName); + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + ObjectWriteResponse objectInfo = null; + try { + try { + objectInfo = + client.putObject( + PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + checkObjectLegalHold(bucketNameWithLock, objectName, true); + client.disableObjectLegalHold( + DisableObjectLegalHoldArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .build()); + mintSuccessLog(methodName, null, startTime); + } finally { + if (objectInfo != null) { + client.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .versionId(objectInfo.versionId()) + .build()); + } + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void disableObjectLegalHold() throws Exception { + if (bucketNameWithLock == null) return; + + String methodName = "disableObjectLegalHold()"; + if (!MINT_ENV) System.out.println(methodName); + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + ObjectWriteResponse objectInfo = null; + try { + try { + objectInfo = + client.putObject( + PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + checkObjectLegalHold(bucketNameWithLock, objectName, false); + client.enableObjectLegalHold( + EnableObjectLegalHoldArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .build()); + checkObjectLegalHold(bucketNameWithLock, objectName, false); + mintSuccessLog(methodName, null, startTime); + } finally { + if (objectInfo != null) { + client.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .versionId(objectInfo.versionId()) + .build()); + } + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void isObjectLegalHoldEnabled() throws Exception { + if (bucketNameWithLock == null) return; + + String methodName = "isObjectLegalHoldEnabled()"; + if (!MINT_ENV) System.out.println(methodName); + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + ObjectWriteResponse objectInfo = null; + try { + try { + objectInfo = + client.putObject( + PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + boolean result = + client.isObjectLegalHoldEnabled( + IsObjectLegalHoldEnabledArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .build()); + Assert.assertFalse("object legal hold: expected: false, got: " + result, result); + checkObjectLegalHold(bucketNameWithLock, objectName, true); + checkObjectLegalHold(bucketNameWithLock, objectName, false); + mintSuccessLog(methodName, null, startTime); + } finally { + if (objectInfo != null) { + client.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .versionId(objectInfo.versionId()) + .build()); + } + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setObjectLockConfiguration() throws Exception { + String methodName = "setObjectLockConfiguration()"; + String testTags = "[COMPLIANCE, 10 days]"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); + try { + ObjectLockConfiguration config = + new ObjectLockConfiguration( + RetentionMode.COMPLIANCE, new ObjectLockConfiguration.RetentionDurationDays(10)); + client.setObjectLockConfiguration( + SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build()); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + mintSuccessLog(methodName, testTags, startTime); + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void testGetObjectLockConfiguration( + String bucketName, RetentionMode mode, ObjectLockConfiguration.RetentionDuration duration) + throws Exception { + ObjectLockConfiguration expectedConfig = new ObjectLockConfiguration(mode, duration); + client.setObjectLockConfiguration( + SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(expectedConfig).build()); + ObjectLockConfiguration config = + client.getObjectLockConfiguration( + GetObjectLockConfigurationArgs.builder().bucket(bucketName).build()); + Assert.assertEquals( + "retention mode: expected: " + expectedConfig.mode() + ", got: " + config.mode(), + config.mode(), + expectedConfig.mode()); + Assert.assertFalse( + "retention duration: " + expectedConfig.duration() + ", got: " + config.duration(), + config.duration().unit() != expectedConfig.duration().unit() + || config.duration().duration() != expectedConfig.duration().duration()); + } + + public void getObjectLockConfiguration() throws Exception { + String methodName = "getObjectLockConfiguration()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); + try { + testGetObjectLockConfiguration( + bucketName, + RetentionMode.COMPLIANCE, + new ObjectLockConfiguration.RetentionDurationDays(10)); + testGetObjectLockConfiguration( + bucketName, + RetentionMode.GOVERNANCE, + new ObjectLockConfiguration.RetentionDurationYears(1)); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteObjectLockConfiguration() throws Exception { + String methodName = "deleteObjectLockConfiguration()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); + try { + client.deleteObjectLockConfiguration( + DeleteObjectLockConfigurationArgs.builder().bucket(bucketName).build()); + ObjectLockConfiguration config = + new ObjectLockConfiguration( + RetentionMode.COMPLIANCE, new ObjectLockConfiguration.RetentionDurationDays(10)); + client.setObjectLockConfiguration( + SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build()); + client.deleteObjectLockConfiguration( + DeleteObjectLockConfigurationArgs.builder().bucket(bucketName).build()); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setObjectRetention() throws Exception { + if (bucketNameWithLock == null) return; + + String methodName = "setObjectRetention()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + ObjectWriteResponse objectInfo = null; + try { + try { + objectInfo = + client.putObject( + PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + client.setObjectRetention( + SetObjectRetentionArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .config( + new Retention( + RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(1))) + .build()); + + client.setObjectRetention( + SetObjectRetentionArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .config(new Retention()) + .bypassGovernanceMode(true) + .build()); + } finally { + if (objectInfo != null) { + client.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .versionId(objectInfo.versionId()) + .build()); + } + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void testGetObjectRetention(SetObjectRetentionArgs args) throws Exception { + client.setObjectRetention(args); + Retention config = + client.getObjectRetention( + GetObjectRetentionArgs.builder().bucket(args.bucket()).object(args.object()).build()); + + if (args.config().mode() == null) { + Assert.assertFalse( + "retention mode: expected: , got: " + config.mode(), + config != null && config.mode() != null); + } else { + Assert.assertEquals( + "retention mode: expected: " + args.config().mode() + ", got: " + config.mode(), + args.config().mode(), + config.mode()); + } + + ZonedDateTime expectedDate = args.config().retainUntilDate(); + ZonedDateTime date = (config == null) ? null : config.retainUntilDate(); + + if (expectedDate == null) { + Assert.assertNull("retention retain-until-date: expected: , got: " + date, date); + } else { + Assert.assertEquals( + "retention retain-until-date: expected: " + + expectedDate.withNano(0) + + ", got: " + + date.withNano(0), + date.withNano(0), + expectedDate.withNano(0)); + } + } + + public void getObjectRetention() throws Exception { + if (bucketNameWithLock == null) return; + + String methodName = "getObjectRetention()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + ObjectWriteResponse objectInfo = null; + try { + try { + objectInfo = + client.putObject( + PutObjectArgs.builder().bucket(bucketNameWithLock).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + testGetObjectRetention( + SetObjectRetentionArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .config( + new Retention( + RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(3))) + .build()); + + // Check shortening retention until period + testGetObjectRetention( + SetObjectRetentionArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .config( + new Retention( + RetentionMode.GOVERNANCE, ZonedDateTime.now(Time.UTC).plusDays(1))) + .bypassGovernanceMode(true) + .build()); + + // Check empty retention. + // Enable below test when minio server release has a fix. + // testGetObjectRetention( + // SetObjectRetentionArgs.builder() + // .bucket(bucketNameWithLock) + // .object(objectName) + // .config(new Retention()) + // .bypassGovernanceMode(true) + // .build()); + } finally { + if (objectInfo != null) { + client.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketNameWithLock) + .object(objectName) + .versionId(objectInfo.versionId()) + .bypassGovernanceMode(true) + .build()); + } + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketPolicy() throws Exception { + String methodName = "getBucketPolicy()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + String config = + client.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build()); + Assert.assertTrue("policy: expected: \"\", got: " + config, config.isEmpty()); + String policy = + "{'Version':'2012-10-17','Statement':[{'Action':['s3:GetObject'],'Effect':'Allow'," + + "'Principal':{'AWS':['*']},'Resource':['arn:aws:s3:::" + + bucketName + + "/myobject*'],'Sid':''}]}"; + policy = policy.replaceAll("'", "\""); + client.setBucketPolicy( + SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build()); + client.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setBucketPolicy() throws Exception { + String methodName = "setBucketPolicy()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + String policy = + "{'Version':'2012-10-17','Statement':[{'Action':['s3:GetObject'],'Effect':'Allow'," + + "'Principal':{'AWS':['*']},'Resource':['arn:aws:s3:::" + + bucketName + + "/myobject*'],'Sid':''}]}"; + policy = policy.replaceAll("'", "\""); + client.setBucketPolicy( + SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteBucketPolicy() throws Exception { + String methodName = "deleteBucketPolicy()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + client.deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket(bucketName).build()); + + String policy = + "{'Version':'2012-10-17','Statement':[{'Action':['s3:GetObject'],'Effect':'Allow'," + + "'Principal':{'AWS':['*']},'Resource':['arn:aws:s3:::" + + bucketName + + "/myobject*'],'Sid':''}]}"; + policy = policy.replaceAll("'", "\""); + client.setBucketPolicy( + SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build()); + client.deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket(bucketName).build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void testSetBucketLifecycle(String bucketName, LifecycleConfiguration.Rule... rules) + throws Exception { + LifecycleConfiguration config = new LifecycleConfiguration(Arrays.asList(rules)); + client.setBucketLifecycle( + SetBucketLifecycleArgs.builder().bucket(bucketName).config(config).build()); + } + + public void setBucketLifecycle() throws Exception { + String methodName = "setBucketLifecycle()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + testSetBucketLifecycle( + bucketName, + new LifecycleConfiguration.Rule( + Status.ENABLED, + null, + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), + "rule2", + null, + null, + null)); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteBucketLifecycle() throws Exception { + String methodName = "deleteBucketLifecycle()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + client.deleteBucketLifecycle( + DeleteBucketLifecycleArgs.builder().bucket(bucketName).build()); + testSetBucketLifecycle( + bucketName, + new LifecycleConfiguration.Rule( + Status.ENABLED, + null, + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), + "rule2", + null, + null, + null)); + client.deleteBucketLifecycle( + DeleteBucketLifecycleArgs.builder().bucket(bucketName).build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketLifecycle() throws Exception { + String methodName = "getBucketLifecycle()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + LifecycleConfiguration config = + client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); + Assert.assertNull("config: expected: , got: ", config); + testSetBucketLifecycle( + bucketName, + new LifecycleConfiguration.Rule( + Status.ENABLED, + null, + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), + "rule2", + null, + null, + null)); + config = + client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); + Assert.assertNotNull("config: expected: , got: ", config); + List rules = config.rules(); + Assert.assertEquals( + "config.rules().size(): expected: 1, got: " + config.rules().size(), + 1, + config.rules().size()); + LifecycleConfiguration.Rule rule = rules.get(0); + Assert.assertEquals( + "rule.status(): expected: " + Status.ENABLED + ", got: " + rule.status(), + rule.status(), + Status.ENABLED); + Assert.assertNotNull( + "rule.expiration(): expected: , got: ", rule.expiration()); + Assert.assertEquals( + "rule.expiration().days(): expected: 365, got: " + rule.expiration().days(), + rule.expiration().days(), + Integer.valueOf(365)); + Assert.assertNotNull("rule.filter(): expected: , got: ", rule.filter()); + Assert.assertEquals( + "rule.filter().prefix(): expected: logs/, got: " + rule.filter().prefix(), + "logs/", + rule.filter().prefix()); + Assert.assertEquals("rule.id(): expected: rule2, got: " + rule.id(), "rule2", rule.id()); + + testSetBucketLifecycle( + bucketName, + new LifecycleConfiguration.Rule( + Status.ENABLED, + null, + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter(""), + null, + null, + null, + null)); + config = + client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); + Assert.assertNotNull("config: expected: , got: ", config); + Assert.assertEquals( + "config.rules().size(): expected: 1, got: " + config.rules().size(), + config.rules().size(), + 1); + Assert.assertNotNull( + "rule.filter(): expected: , got: ", config.rules().get(0).filter()); + Assert.assertEquals( + "rule.filter().prefix(): expected: , got: " + + config.rules().get(0).filter().prefix(), + "", + config.rules().get(0).filter().prefix()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setBucketNotification() throws Exception { + String methodName = "setBucketNotification()"; + long startTime = System.currentTimeMillis(); + if (sqsArn == null) { + mintIgnoredLog(methodName, null, startTime); + return; + } + + if (!MINT_ENV) System.out.println(methodName); + + try { + String bucketName = getRandomName(); + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); + try { + NotificationConfiguration config = + new NotificationConfiguration( + null, + Arrays.asList( + new NotificationConfiguration.QueueConfiguration[] { + new NotificationConfiguration.QueueConfiguration( + sqsArn, + null, + Arrays.asList( + new String[] { + EventType.OBJECT_CREATED_PUT.toString(), + EventType.OBJECT_CREATED_COPY.toString() + }), + new NotificationConfiguration.Filter("images", "pg")) + }), + null, + null); + client.setBucketNotification( + SetBucketNotificationArgs.builder().bucket(bucketName).config(config).build()); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketNotification() throws Exception { + String methodName = "getBucketNotification()"; + long startTime = System.currentTimeMillis(); + if (sqsArn == null) { + mintIgnoredLog(methodName, null, startTime); + return; + } + + if (!MINT_ENV) System.out.println(methodName); + + try { + String bucketName = getRandomName(); + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); + try { + NotificationConfiguration expectedConfig = + new NotificationConfiguration( + null, + Arrays.asList( + new NotificationConfiguration.QueueConfiguration[] { + new NotificationConfiguration.QueueConfiguration( + sqsArn, + null, + Arrays.asList(new String[] {EventType.OBJECT_CREATED_PUT.toString()}), + new NotificationConfiguration.Filter("images", "pg")) + }), + null, + null); + client.setBucketNotification( + SetBucketNotificationArgs.builder().bucket(bucketName).config(expectedConfig).build()); + + NotificationConfiguration config = + client.getBucketNotification( + GetBucketNotificationArgs.builder().bucket(bucketName).build()); + + if (config.queueConfigurations().size() != 1 + || !sqsArn.equals(config.queueConfigurations().get(0).queue()) + || config.queueConfigurations().get(0).events().size() != 1 + || !EventType.OBJECT_CREATED_PUT + .toString() + .equals(config.queueConfigurations().get(0).events().get(0))) { + System.out.println( + "config: expected: " + Xml.marshal(expectedConfig) + ", got: " + Xml.marshal(config)); + } + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteBucketNotification() throws Exception { + String methodName = "deleteBucketNotification()"; + long startTime = System.currentTimeMillis(); + if (sqsArn == null) { + mintIgnoredLog(methodName, null, startTime); + return; + } + + if (!MINT_ENV) System.out.println(methodName); + + try { + String bucketName = getRandomName(); + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); + try { + NotificationConfiguration config = + new NotificationConfiguration( + null, + Arrays.asList( + new NotificationConfiguration.QueueConfiguration[] { + new NotificationConfiguration.QueueConfiguration( + sqsArn, + null, + Arrays.asList( + new String[] { + EventType.OBJECT_CREATED_PUT.toString(), + EventType.OBJECT_CREATED_COPY.toString() + }), + new NotificationConfiguration.Filter("images", "pg")) + }), + null, + null); + client.setBucketNotification( + SetBucketNotificationArgs.builder().bucket(bucketName).config(config).build()); + + client.deleteBucketNotification( + DeleteBucketNotificationArgs.builder().bucket(bucketName).build()); + + config = + client.getBucketNotification( + GetBucketNotificationArgs.builder().bucket(bucketName).build()); + if (config.queueConfigurations().size() != 0) { + System.out.println("config: expected: , got: " + Xml.marshal(config)); + } + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void listenBucketNotification() throws Exception { + String methodName = "listenBucketNotification()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String file = createFile1Kb(); + String bucketName = getRandomName(); + CloseableIterator> ci = null; + String mintArgs = + "prefix=prefix, suffix=suffix, events={\"s3:ObjectCreated:*\", \"s3:ObjectAccessed:*\"}"; + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).region(region).build()); + + String[] events = {"s3:ObjectCreated:*", "s3:ObjectAccessed:*"}; + ci = + client.listenBucketNotification( + ListenBucketNotificationArgs.builder() + .bucket(bucketName) + .prefix("prefix") + .suffix("suffix") + .events(events) + .build()); + + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object("prefix-random-suffix").stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + + while (ci.hasNext()) { + NotificationRecords records = ci.next().get(); + if (records.events().size() == 0) { + continue; + } + + boolean found = false; + for (NotificationRecords.Event event : records.events()) { + if ("prefix-random-suffix".equals(event.object().key())) { + found = true; + break; + } + } + + if (found) break; + } + + mintSuccessLog(methodName, mintArgs, startTime); + } catch (Exception e) { + handleException(methodName, mintArgs, startTime, e); + } finally { + if (ci != null) ci.close(); + + Files.delete(Paths.get(file)); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object("prefix-random-suffix").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } + + public void selectObjectContent() throws Exception { + String methodName = "selectObjectContent()"; + String sqlExpression = "select * from S3Object"; + String testArgs = "[sqlExpression: " + sqlExpression + ", requestProgress: true]"; + + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + SelectResponseStream responseStream = null; + try { + String expectedResult = + "1997,Ford,E350,\"ac, abs, moon\",3000.00\n" + + "1999,Chevy,\"Venture \"\"Extended Edition\"\"\",,4900.00\n" + + "1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00\n" + + "1996,Jeep,Grand Cherokee,\"MUST SELL!\n" + + "air, moon roof, loaded\",4799.00\n"; + byte[] data = + ("Year,Make,Model,Description,Price\n" + expectedResult).getBytes(StandardCharsets.UTF_8); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + bais, (long) data.length, null) + .build()); + + InputSerialization is = + InputSerialization.newCSV( + null, false, null, null, InputSerialization.FileHeaderInfo.USE, null, null, null); + OutputSerialization os = + OutputSerialization.newCSV( + null, null, null, OutputSerialization.QuoteFields.ASNEEDED, null); + + responseStream = + client.selectObjectContent( + SelectObjectContentArgs.builder() + .bucket(bucketName) + .object(objectName) + .sqlExpression(sqlExpression) + .inputSerialization(is) + .outputSerialization(os) + .requestProgress(true) + .build()); + + String result = new String(readAllBytes(responseStream), StandardCharsets.UTF_8); + Assert.assertEquals( + "result mismatch; expected: " + expectedResult + ", got: " + result, + result, + expectedResult); + + Stats stats = responseStream.stats(); + Assert.assertNotNull("stats is null", stats); + Assert.assertTrue( + "stats.bytesScanned mismatch; expected: 258, got: " + stats.bytesScanned(), + stats.bytesScanned() == 256); + Assert.assertTrue( + "stats.bytesProcessed mismatch; expected: 258, got: " + stats.bytesProcessed(), + stats.bytesProcessed() == 256); + Assert.assertTrue( + "stats.bytesReturned mismatch; expected: 222, got: " + stats.bytesReturned(), + stats.bytesReturned() == 222); + mintSuccessLog(methodName, testArgs, startTime); + } catch (Exception e) { + handleException(methodName, testArgs, startTime, e); + } finally { + if (responseStream != null) responseStream.close(); + client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } + + public void setBucketEncryption() throws Exception { + String methodName = "setBucketEncryption()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + client.setBucketEncryption( + SetBucketEncryptionArgs.builder() + .bucket(bucketName) + .config(SseConfiguration.newConfigWithSseS3Rule()) + .build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketEncryption() throws Exception { + String methodName = "getBucketEncryption()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + SseConfiguration config = + client.getBucketEncryption( + GetBucketEncryptionArgs.builder().bucket(bucketName).build()); + Assert.assertNull("rule: expected: , got: ", config.rule()); + client.setBucketEncryption( + SetBucketEncryptionArgs.builder() + .bucket(bucketName) + .config(SseConfiguration.newConfigWithSseS3Rule()) + .build()); + config = + client.getBucketEncryption( + GetBucketEncryptionArgs.builder().bucket(bucketName).build()); + Assert.assertNotNull("rule: expected: , got: ", config.rule()); + Assert.assertEquals( + "sse algorithm: expected: " + + SseAlgorithm.AES256 + + ", got: " + + config.rule().sseAlgorithm(), + config.rule().sseAlgorithm(), + SseAlgorithm.AES256); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteBucketEncryption() throws Exception { + String methodName = "deleteBucketEncryption()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + client.deleteBucketEncryption( + DeleteBucketEncryptionArgs.builder().bucket(bucketName).build()); + + client.setBucketEncryption( + SetBucketEncryptionArgs.builder() + .bucket(bucketName) + .config(SseConfiguration.newConfigWithSseS3Rule()) + .build()); + client.deleteBucketEncryption( + DeleteBucketEncryptionArgs.builder().bucket(bucketName).build()); + SseConfiguration config = + client.getBucketEncryption( + GetBucketEncryptionArgs.builder().bucket(bucketName).build()); + Assert.assertNull("rule: expected: , got: ", config.rule()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void testBucketCors(String methodName, boolean getTest, boolean deleteTest) + throws Exception { + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + CORSConfiguration expectedConfig = + new CORSConfiguration( + Arrays.asList( + new CORSConfiguration.CORSRule[] { + // Rule 1 + new CORSConfiguration.CORSRule( + Arrays.asList(new String[] {"*"}), // Allowed headers + Arrays.asList(new String[] {"PUT", "POST", "DELETE"}), // Allowed methods + Arrays.asList(new String[] {"http://www.example.com"}), // Allowed origins + Arrays.asList( + new String[] {"x-amz-server-side-encryption"}), // Expose headers + null, // ID + 3000), // Maximum age seconds + // Rule 2 + new CORSConfiguration.CORSRule( + null, // Allowed headers + Arrays.asList(new String[] {"GET"}), // Allowed methods + Arrays.asList(new String[] {"*"}), // Allowed origins + null, // Expose headers + null, // ID + null // Maximum age seconds + ) + })); + client.setBucketCors( + SetBucketCorsArgs.builder().bucket(bucketName).config(expectedConfig).build()); + if (getTest) { + CORSConfiguration config = + client.getBucketCors(GetBucketCorsArgs.builder().bucket(bucketName).build()); + Assert.assertEquals( + "cors: expected: " + expectedConfig + ", got: " + config, expectedConfig, config); + } + if (deleteTest) { + client.deleteBucketCors(DeleteBucketCorsArgs.builder().bucket(bucketName).build()); + } + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setBucketCors() throws Exception { + testBucketCors("setBucketCors()", false, false); + } + + public void getBucketCors() throws Exception { + testBucketCors("getBucketCors()", true, false); + } + + public void deleteBucketCors() throws Exception { + testBucketCors("deleteBucketCors()", false, true); + } + + public void setBucketTags() throws Exception { + String methodName = "setBucketTags()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(map).build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketTags() throws Exception { + String methodName = "getBucketTags()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + Map map = new HashMap<>(); + Tags tags = client.getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build()); + Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); + + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(map).build()); + tags = client.getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build()); + Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteBucketTags() throws Exception { + String methodName = "deleteBucketTags()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String bucketName = getRandomName(); + try { + client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + try { + client.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket(bucketName).build()); + + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.setBucketTags(SetBucketTagsArgs.builder().bucket(bucketName).tags(map).build()); + client.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket(bucketName).build()); + Tags tags = client.getBucketTags(GetBucketTagsArgs.builder().bucket(bucketName).build()); + Assert.assertTrue("tags: expected: " + ", got: " + tags.get(), tags.get().isEmpty()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setObjectTags() throws Exception { + String methodName = "setObjectTags()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + try { + try { + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.setObjectTags( + SetObjectTagsArgs.builder().bucket(bucketName).object(objectName).tags(map).build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getObjectTags() throws Exception { + String methodName = "getObjectTags()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + try { + try { + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + Map map = new HashMap<>(); + Tags tags = + client.getObjectTags( + GetObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); + Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); + + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.setObjectTags( + SetObjectTagsArgs.builder().bucket(bucketName).object(objectName).tags(map).build()); + tags = + client.getObjectTags( + GetObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); + Assert.assertEquals("tags: expected: " + map + ", got: " + tags.get(), map, tags.get()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteObjectTags() throws Exception { + String methodName = "deleteObjectTags()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + try { + try { + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + client.deleteObjectTags( + DeleteObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); + + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.setObjectTags( + SetObjectTagsArgs.builder().bucket(bucketName).object(objectName).tags(map).build()); + client.deleteObjectTags( + DeleteObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); + Tags tags = + client.getObjectTags( + GetObjectTagsArgs.builder().bucket(bucketName).object(objectName).build()); + Assert.assertTrue("tags: expected: , got: " + tags.get(), tags.get().isEmpty()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getObjectAcl() throws Exception { + String methodName = "getObjectAcl()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + try { + try { + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + AccessControlPolicy policy = + client.getObjectAcl( + GetObjectAclArgs.builder().bucket(bucketName).object(objectName).build()); + Assert.assertEquals( + "granteeType: expected: " + + AccessControlList.Type.CANONICAL_USER + + ", got: " + + policy.accessControlList().grants().get(0).grantee().type(), + policy.accessControlList().grants().get(0).grantee().type(), + AccessControlList.Type.CANONICAL_USER); + Assert.assertEquals( + "permission: expected: " + + AccessControlList.Permission.FULL_CONTROL + + ", got: " + + policy.accessControlList().grants().get(0).permission(), + policy.accessControlList().grants().get(0).permission(), + AccessControlList.Permission.FULL_CONTROL); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getObjectAttributes() throws Exception { + String methodName = "getObjectAttributes()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName = getRandomName(); + try { + try { + client.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + new ContentInputStream(1 * KB), 1L * KB, null) + .build()); + GetObjectAttributesResponse response = + client.getObjectAttributes( + GetObjectAttributesArgs.builder() + .bucket(bucketName) + .object(objectName) + .objectAttributes( + new String[] { + "ETag", "Checksum", "ObjectParts", "StorageClass", "ObjectSize" + }) + .build()); + Assert.assertTrue( + "objectSize: expected: " + (1 * KB) + ", got: " + response.result().objectSize(), + response.result().objectSize() == (1 * KB)); + Assert.assertTrue( + "partNumber: expected: 1, got: " + + response.result().objectParts().parts().get(0).partNumber(), + response.result().objectParts().parts().get(0).partNumber() == 1); + Assert.assertTrue( + "partSize: expected: " + + (1 * KB) + + ", got: " + + response.result().objectParts().parts().get(0).partSize(), + response.result().objectParts().parts().get(0).partSize() == (1 * KB)); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void setBucketReplication() throws Exception { + String methodName = "setBucketReplication()"; + if (!MINT_ENV) System.out.println(methodName); + + if (REPLICATION_SRC_BUCKET == null + || REPLICATION_ROLE == null + || REPLICATION_BUCKET_ARN == null) { + mintIgnoredLog(methodName, "", System.currentTimeMillis()); + return; + } + + long startTime = System.currentTimeMillis(); + try { + Map tags = new HashMap<>(); + tags.put("key1", "value1"); + tags.put("key2", "value2"); + + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, REPLICATION_BUCKET_ARN, null, null, null, null), + null, + new Filter(new Filter.And("TaxDocs", tags)), + "rule1", + null, + 1, + null, + Status.ENABLED); + + List rules = new LinkedList<>(); + rules.add(rule); + + ReplicationConfiguration config = new ReplicationConfiguration(REPLICATION_ROLE, rules); + + client.setBucketReplication( + SetBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).config(config).build()); + client.deleteBucketReplication( + DeleteBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void getBucketReplication() throws Exception { + String methodName = "getBucketReplication()"; + if (!MINT_ENV) System.out.println(methodName); + + if (REPLICATION_SRC_BUCKET == null + || REPLICATION_ROLE == null + || REPLICATION_BUCKET_ARN == null) { + mintIgnoredLog(methodName, "", System.currentTimeMillis()); + return; + } + + long startTime = System.currentTimeMillis(); + try { + ReplicationConfiguration config = + client.getBucketReplication( + GetBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + Assert.assertNull("config: expected: , got: ", config); + + Map tags = new HashMap<>(); + tags.put("key1", "value1"); + tags.put("key2", "value2"); + + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, REPLICATION_BUCKET_ARN, null, null, null, null), + null, + new Filter(new Filter.And("TaxDocs", tags)), + "rule1", + null, + 1, + null, + Status.ENABLED); + + List rules = new LinkedList<>(); + rules.add(rule); + + config = new ReplicationConfiguration(REPLICATION_ROLE, rules); + client.setBucketReplication( + SetBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).config(config).build()); + config = + client.getBucketReplication( + GetBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + Assert.assertNotNull("config: expected: , got: ", config); + client.deleteBucketReplication( + DeleteBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void deleteBucketReplication() throws Exception { + String methodName = "deleteBucketReplication()"; + if (!MINT_ENV) System.out.println(methodName); + + if (REPLICATION_SRC_BUCKET == null + || REPLICATION_ROLE == null + || REPLICATION_BUCKET_ARN == null) { + mintIgnoredLog(methodName, "", System.currentTimeMillis()); + return; + } + + long startTime = System.currentTimeMillis(); + try { + client.deleteBucketReplication( + DeleteBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + + Map tags = new HashMap<>(); + tags.put("key1", "value1"); + tags.put("key2", "value2"); + + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, REPLICATION_BUCKET_ARN, null, null, null, null), + null, + new Filter(new Filter.And("TaxDocs", tags)), + "rule1", + null, + 1, + null, + Status.ENABLED); + + List rules = new LinkedList<>(); + rules.add(rule); + + ReplicationConfiguration config = new ReplicationConfiguration(REPLICATION_ROLE, rules); + client.setBucketReplication( + SetBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).config(config).build()); + client.deleteBucketReplication( + DeleteBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + config = + client.getBucketReplication( + GetBucketReplicationArgs.builder().bucket(REPLICATION_SRC_BUCKET).build()); + Assert.assertNull("config: expected: , got: ", config); + mintSuccessLog(methodName, null, startTime); + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void testUploadSnowballObjects(String testTags, boolean compression) throws Exception { + String methodName = "uploadSnowballObjects()"; + + long startTime = System.currentTimeMillis(); + String objectName1 = getRandomName(); + String objectName2 = getRandomName(); + try { + try { + List objects = new LinkedList(); + objects.add( + new SnowballObject( + objectName1, + new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)), + 5, + null)); + objects.add(new SnowballObject(objectName2, createFile1Kb())); + client.uploadSnowballObjects( + UploadSnowballObjectsArgs.builder() + .bucket(bucketName) + .objects(objects) + .compression(compression) + .build()); + + StatObjectResponse stat = + client.statObject( + StatObjectArgs.builder().bucket(bucketName).object(objectName1).build()); + Assert.assertEquals("object size: expected: 5, got: " + stat.size(), 5, stat.size()); + stat = + client.statObject( + StatObjectArgs.builder().bucket(bucketName).object(objectName2).build()); + Assert.assertEquals( + "object size: expected: " + KB + ", got: " + stat.size(), 1 * KB, stat.size()); + mintSuccessLog(methodName, testTags, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName1).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName2).build()); + } + } catch (Exception e) { + handleException(methodName, testTags, startTime, e); + } + } + + public void uploadSnowballObjects() throws Exception { + String methodName = "uploadSnowballObjects()"; + if (!MINT_ENV) System.out.println(methodName); + + testUploadSnowballObjects("[no compression]", false); + testUploadSnowballObjects("[compression]", true); + } + + public void putObjectFanOut() throws Exception { + String methodName = "putObjectFanOut()"; + if (!MINT_ENV) System.out.println(methodName); + + long startTime = System.currentTimeMillis(); + String objectName1 = getRandomName(); + String objectName2 = getRandomName(); + try { + try { + Map map = new HashMap<>(); + map.put("Project", "Project One"); + map.put("User", "jsmith"); + client.putObjectFanOut( + PutObjectFanOutArgs.builder().bucket(bucketName).stream( + new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8)), 5) + .entries( + Arrays.asList( + new PutObjectFanOutEntry[] { + PutObjectFanOutEntry.builder().key(objectName1).userMetadata(map).build(), + PutObjectFanOutEntry.builder().key(objectName2).tags(map).build() + })) + .build()); + + StatObjectResponse stat = + client.statObject( + StatObjectArgs.builder().bucket(bucketName).object(objectName1).build()); + Assert.assertTrue( + "userMetadata: expected = " + map + ", got = " + stat.userMetadata(), + map.size() == stat.userMetadata().size() + && map.entrySet().stream() + .allMatch(e -> e.getValue().equals(stat.userMetadata().getFirst(e.getKey())))); + + Tags tags = + client.getObjectTags( + GetObjectTagsArgs.builder().bucket(bucketName).object(objectName2).build()); + Assert.assertTrue( + "tags: expected = " + map + ", got = " + tags.get(), map.equals(tags.get())); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName1).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(objectName2).build()); + } + } catch (Exception e) { + handleException(methodName, null, startTime, e); + } + } + + public void runBucketTests() throws Exception { + makeBucket(); + bucketExists(); + removeBucket(); + listBuckets(); + + setBucketVersioning(); + getBucketVersioning(); + + setObjectLockConfiguration(); + getObjectLockConfiguration(); + + setBucketEncryption(); + getBucketEncryption(); + deleteBucketEncryption(); + + setBucketCors(); + getBucketCors(); + deleteBucketCors(); + + setBucketTags(); + getBucketTags(); + deleteBucketTags(); + + setBucketPolicy(); + getBucketPolicy(); + deleteBucketPolicy(); + + setBucketLifecycle(); + getBucketLifecycle(); + deleteBucketLifecycle(); + + setBucketNotification(); + getBucketNotification(); + deleteBucketNotification(); + + setBucketReplication(); + getBucketReplication(); + deleteBucketReplication(); + + listenBucketNotification(); + } + + public void runObjectTests() throws Exception { + listObjects(); + + setup(); + + putObject(); + getObject(); + removeObject(); + removeObjects(); + statObject(); + + copyObject(); + composeObject(); + uploadObject(); + downloadObject(); + + setObjectRetention(); + getObjectRetention(); + + getPresignedObjectUrl(); + getPresignedPostFormData(); + + enableObjectLegalHold(); + disableObjectLegalHold(); + isObjectLegalHoldEnabled(); + + selectObjectContent(); + + setObjectTags(); + getObjectTags(); + deleteObjectTags(); + + getObjectAcl(); + getObjectAttributes(); + + uploadSnowballObjects(); + putObjectFanOut(); + + teardown(); + } + + public void runTests() throws Exception { + runBucketTests(); + runObjectTests(); + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e18bc253b..d4081da47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6d6..f3b75f3b0 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum