diff --git a/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java b/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java index de11bd275..26a5860ff 100644 --- a/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java +++ b/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java @@ -27,18 +27,15 @@ 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.Http; import io.minio.Signer; import io.minio.Time; +import io.minio.Utils; import io.minio.admin.messages.DataUsageInfo; import io.minio.admin.messages.info.Message; 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 java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -115,7 +112,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; @@ -138,7 +135,7 @@ private Credentials getCredentials() { } private Response execute( - Method method, Command command, Multimap queryParamMap, byte[] body) + Http.Method method, Command command, Multimap queryParamMap, byte[] body) throws InvalidKeyException, IOException, NoSuchAlgorithmException { Credentials creds = getCredentials(); @@ -146,32 +143,32 @@ private Response execute( 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", Utils.sha256Hash(body, 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", Utils.ZERO_SHA256_HASH); } Request request = requestBuilder.build(); @@ -251,7 +248,7 @@ 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()))) {} @@ -270,7 +267,10 @@ public UserInfo getUserInfo(String accessKey) throws NoSuchAlgorithmException, InvalidKeyException, IOException { 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); } @@ -288,7 +288,7 @@ public UserInfo getUserInfo(String accessKey) public Map listUsers() throws NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidCipherTextException { - try (Response response = execute(Method.GET, Command.LIST_USERS, null, null)) { + 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 = @@ -315,7 +315,7 @@ public void deleteUser(@Nonnull String accessKey) try (Response response = execute( - Method.DELETE, + Http.Method.DELETE, Command.REMOVE_USER, ImmutableMultimap.of("accessKey", accessKey), null)) {} @@ -342,7 +342,7 @@ public void addUpdateGroup( try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_UPDATE_REMOVE_GROUP, null, OBJECT_MAPPER.writeValueAsBytes(groupAddUpdateRemoveInfo))) {} @@ -360,7 +360,7 @@ public void addUpdateGroup( public GroupInfo getGroupInfo(String group) throws NoSuchAlgorithmException, InvalidKeyException, IOException { 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); } @@ -376,7 +376,7 @@ public GroupInfo getGroupInfo(String group) */ public List listGroups() throws NoSuchAlgorithmException, InvalidKeyException, IOException { - try (Response response = execute(Method.GET, Command.LIST_GROUPS, null, null)) { + 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); @@ -402,7 +402,7 @@ public void removeGroup(@Nonnull String group) try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.ADD_UPDATE_REMOVE_GROUP, null, OBJECT_MAPPER.writeValueAsBytes(groupAddUpdateRemoveInfo))) {} @@ -427,7 +427,7 @@ public void setBucketQuota(@Nonnull String bucketName, long size, @Nonnull Quota 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))) {} @@ -446,7 +446,7 @@ public long getBucketQuota(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { try (Response response = execute( - Method.GET, + Http.Method.GET, Command.GET_BUCKET_QUOTA, ImmutableMultimap.of("bucket", bucketName), null)) { @@ -513,7 +513,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))) {} @@ -541,7 +541,7 @@ public void setPolicy( try (Response response = execute( - Method.PUT, + Http.Method.PUT, Command.SET_USER_OR_GROUP_POLICY, ImmutableMultimap.of( "userOrGroup", @@ -564,7 +564,7 @@ public void setPolicy( */ public Map listCannedPolicies() throws NoSuchAlgorithmException, InvalidKeyException, IOException { - try (Response response = execute(Method.GET, Command.LIST_CANNED_POLICIES, null, null)) { + try (Response response = execute(Http.Method.GET, Command.LIST_CANNED_POLICIES, null, null)) { MapType mapType = OBJECT_MAPPER .getTypeFactory() @@ -593,7 +593,7 @@ public void removeCannedPolicy(@Nonnull String name) try (Response response = execute( - Method.DELETE, + Http.Method.DELETE, Command.REMOVE_CANNED_POLICY, ImmutableMultimap.of("name", name), null)) {} @@ -609,7 +609,7 @@ public void removeCannedPolicy(@Nonnull String name) */ public DataUsageInfo getDataUsageInfo() throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try (Response response = execute(Method.GET, Command.DATA_USAGE_INFO, null, null)) { + try (Response response = execute(Http.Method.GET, Command.DATA_USAGE_INFO, null, null)) { return OBJECT_MAPPER.readValue(response.body().bytes(), DataUsageInfo.class); } } @@ -623,7 +623,7 @@ public DataUsageInfo getDataUsageInfo() * @throws IOException thrown to indicate I/O error on MinIO REST operation. */ public Message getServerInfo() throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try (Response response = execute(Method.GET, Command.INFO, null, null)) { + try (Response response = execute(Http.Method.GET, Command.INFO, null, null)) { return OBJECT_MAPPER.readValue(response.body().charStream(), Message.class); } } @@ -685,13 +685,13 @@ public Credentials addServiceAccount( 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()))) { @@ -752,13 +752,13 @@ public void updateServiceAccount( 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()))) {} @@ -780,7 +780,7 @@ public void deleteServiceAccount(@Nonnull String accessKey) try (Response response = execute( - Method.DELETE, + Http.Method.DELETE, Command.DELETE_SERVICE_ACCOUNT, ImmutableMultimap.of("accessKey", accessKey), null)) {} @@ -805,7 +805,7 @@ public ListServiceAccountResp listServiceAccount(@Nonnull String username) try (Response response = execute( - Method.GET, + Http.Method.GET, Command.LIST_SERVICE_ACCOUNTS, ImmutableMultimap.of("user", username), null)) { @@ -833,7 +833,7 @@ public GetServiceAccountInfoResp getServiceAccountInfo(@Nonnull String accessKey } try (Response response = execute( - Method.GET, + Http.Method.GET, Command.INFO_SERVICE_ACCOUNT, ImmutableMultimap.of("accessKey", accessKey), null)) { @@ -857,8 +857,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); } /** @@ -873,7 +872,7 @@ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) */ @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.") public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmException { - this.httpClient = HttpUtils.disableCertCheck(this.httpClient); + this.httpClient = Http.disableCertCheck(this.httpClient); } /** @@ -885,8 +884,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(); } /** @@ -923,12 +921,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 +936,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,24 +960,22 @@ 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"); + Utils.validateNotNull(baseUrl, "base url"); + Utils.validateNotNull(provider, "credential provider"); if (httpClient == null) { - httpClient = - HttpUtils.newDefaultHttpClient( - DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); + httpClient = Http.newDefaultClient(); } return new MinioAdminClient(baseUrl, region, provider, httpClient); } diff --git a/api/src/main/java/io/minio/BaseArgs.java b/api/src/main/java/io/minio/BaseArgs.java index c8857ec55..ba9b8875f 100644 --- a/api/src/main/java/io/minio/BaseArgs.java +++ b/api/src/main/java/io/minio/BaseArgs.java @@ -60,75 +60,34 @@ 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); + final Multimap extraHeaders = Utils.newMultimap(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); + final Multimap extraQueryParams = Utils.newMultimap(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); + final Multimap extraHeaders = Utils.newMultimap(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(Map queryParams) { - final Multimap extraQueryParams = toMultimap(queryParams); + final Multimap extraQueryParams = Utils.newMultimap(queryParams); operations.add(args -> args.extraQueryParams = extraQueryParams); return (B) this; } diff --git a/api/src/main/java/io/minio/BucketArgs.java b/api/src/main/java/io/minio/BucketArgs.java index c50bcdfda..ef902729b 100644 --- a/api/src/main/java/io/minio/BucketArgs.java +++ b/api/src/main/java/io/minio/BucketArgs.java @@ -16,8 +16,6 @@ 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; @@ -42,7 +40,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 +53,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 +65,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/Checksum.java b/api/src/main/java/io/minio/Checksum.java new file mode 100644 index 000000000..c29ca05b2 --- /dev/null +++ b/api/src/main/java/io/minio/Checksum.java @@ -0,0 +1,338 @@ +/* + * 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.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Locale; + +/** Collection of checksum algorithms. */ +public class Checksum { + public static String base64String(byte[] sum) { + return Base64.getEncoder().encodeToString(sum); + } + + public static String hexString(byte[] sum) { + StringBuilder builder = new StringBuilder(); + for (byte b : sum) builder.append(String.format("%02x", b)); + return builder.toString(); + } + + /** Algorithm type. */ + public static enum Type { + COMPOSITE, + FULL_OBJECT; + } + + /** Checksum algorithm. */ + public static enum Algorithm { + CRC32, + CRC32C, + CRC64NVME, + SHA1, + SHA256, + MD5; + + public String header() { + if (this == MD5) return "Content-MD5"; + return ("x-amz-checksum-" + this).toLowerCase(Locale.US); + } + + public boolean compositeSupport() { + return this != CRC64NVME && this != MD5; + } + + public Hasher hasher() throws NoSuchAlgorithmException { + 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; + } + } + + public abstract static class Hasher { + public abstract void update(byte[] b, int off, int len); + + public abstract byte[] sum(); + + public void update(byte[] b) { + update(b, 0, b.length); + } + } + + /** CRC32 checksum is java.util.zip.CRC32 compatible to 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 String toString() { + return "CRC32{" + hexString(sum()) + "}"; + } + } + + /** CRC32C checksum. */ + 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 logic 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) { + ByteBuffer byteBuffer = 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()) + "}"; + } + } + + public static class SHA1 extends Hasher { + MessageDigest hasher; + + public SHA1() throws NoSuchAlgorithmException { + this.hasher = MessageDigest.getInstance("SHA-1"); + } + + 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(); + } + + @Override + public String toString() { + return "SHA1{" + hexString(sum()) + "}"; + } + } + + public static class SHA256 extends Hasher { + MessageDigest hasher; + + public SHA256() throws NoSuchAlgorithmException { + this.hasher = MessageDigest.getInstance("SHA-256"); + } + + 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(); + } + + @Override + public String toString() { + return "SHA256{" + hexString(sum()) + "}"; + } + } + + public static class MD5 extends Hasher { + MessageDigest hasher; + + public MD5() throws NoSuchAlgorithmException { + this.hasher = MessageDigest.getInstance("MD5"); + } + + 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(); + } + + @Override + public String toString() { + return "MD5{" + base64String(sum()) + "}"; + } + } +} diff --git a/api/src/main/java/io/minio/CopyObjectArgs.java b/api/src/main/java/io/minio/CopyObjectArgs.java index 2108ab531..080ad7ca4 100644 --- a/api/src/main/java/io/minio/CopyObjectArgs.java +++ b/api/src/main/java/io/minio/CopyObjectArgs.java @@ -69,7 +69,7 @@ public static final class Builder extends ObjectWriteArgs.Builder args.source = source); return this; } 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/DownloadObjectArgs.java b/api/src/main/java/io/minio/DownloadObjectArgs.java index eb9fa6daf..e2d066567 100644 --- a/api/src/main/java/io/minio/DownloadObjectArgs.java +++ b/api/src/main/java/io/minio/DownloadObjectArgs.java @@ -40,7 +40,7 @@ public static Builder builder() { /** Argument class 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/GetObjectAttributesArgs.java b/api/src/main/java/io/minio/GetObjectAttributesArgs.java index 19bd9bbba..143275af1 100644 --- a/api/src/main/java/io/minio/GetObjectAttributesArgs.java +++ b/api/src/main/java/io/minio/GetObjectAttributesArgs.java @@ -51,7 +51,7 @@ public static final class 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/GetPresignedObjectUrlArgs.java b/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java index a6e3d2a23..ed418ecdd 100644 --- a/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java +++ b/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java @@ -16,7 +16,6 @@ package io.minio; -import io.minio.http.Method; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -28,10 +27,10 @@ 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; } @@ -46,8 +45,8 @@ public static Builder builder() { /** Argument 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/http/HttpUtils.java b/api/src/main/java/io/minio/Http.java similarity index 68% rename from api/src/main/java/io/minio/http/HttpUtils.java rename to api/src/main/java/io/minio/Http.java index b69f3d2c2..e54dfa9b2 100644 --- a/api/src/main/java/io/minio/http/HttpUtils.java +++ b/api/src/main/java/io/minio/Http.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package io.minio.http; +package io.minio; -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.io.InputStream; import java.security.GeneralSecurityException; import java.security.KeyManagementException; import java.security.KeyStore; @@ -31,7 +30,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; +import javax.annotation.Nonnull; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; @@ -41,107 +40,15 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import okhttp3.HttpUrl; +import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Protocol; +import okio.BufferedSink; +import okio.Okio; /** 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(); - } +public class Http { + public static final long DEFAULT_TIMEOUT = TimeUnit.MINUTES.toMillis(5); private static OkHttpClient enableJKSPKCS12Certificates( OkHttpClient httpClient, @@ -264,14 +171,13 @@ public static OkHttpClient enableExternalCertificates(OkHttpClient httpClient, S .build(); } - public static OkHttpClient newDefaultHttpClient( - long connectTimeout, long writeTimeout, long readTimeout) { + public static OkHttpClient newDefaultClient() { OkHttpClient httpClient = new OkHttpClient() .newBuilder() - .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS) - .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS) - .readTimeout(readTimeout, TimeUnit.MILLISECONDS) + .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"); @@ -285,7 +191,9 @@ public static OkHttpClient newDefaultHttpClient( return httpClient; } - @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SIC", + justification = "Should not be used in production anyways.") public static OkHttpClient disableCertCheck(OkHttpClient client) throws KeyManagementException, NoSuchAlgorithmException { final TrustManager[] trustAllCerts = @@ -332,4 +240,60 @@ public static OkHttpClient setTimeout( .readTimeout(readTimeout, TimeUnit.MILLISECONDS) .build(); } + + /** RequestBody that wraps a single data object. */ + public static class RequestBody extends okhttp3.RequestBody { + private InputStream stream; + private byte[] bytes; + private long length; + private MediaType contentType; + + private RequestBody(@Nonnull final MediaType contentType, final long length) { + this.contentType = Utils.validateNotNull(contentType, "content type"); + if (length < 0) throw new IllegalArgumentException("length must not be negative value"); + this.length = length; + } + + public RequestBody( + @Nonnull final byte[] bytes, final int length, @Nonnull final MediaType contentType) { + this(contentType, length); + this.bytes = Utils.validateNotNull(bytes, "data bytes"); + } + + public RequestBody( + @Nonnull final InputStream stream, + final long length, + @Nonnull final MediaType contentType) { + this(contentType, length); + this.stream = Utils.validateNotNull(stream, "stream"); + } + + @Override + public MediaType contentType() { + return contentType; + } + + @Override + public long contentLength() { + return length; + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + if (stream != null) { + sink.write(Okio.source(stream), length); + } else { + sink.write(bytes, 0, (int) length); + } + } + } + + /** HTTP methods. */ + public static enum Method { + GET, + HEAD, + POST, + PUT, + DELETE; + } } 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/ListBucketsArgs.java b/api/src/main/java/io/minio/ListBucketsArgs.java index 539e4192f..0651dcef2 100644 --- a/api/src/main/java/io/minio/ListBucketsArgs.java +++ b/api/src/main/java/io/minio/ListBucketsArgs.java @@ -51,7 +51,7 @@ public static final class Builder extends BaseArgs.Builder args.bucketRegion = region); return this; } @@ -66,13 +66,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/ListObjectsArgs.java b/api/src/main/java/io/minio/ListObjectsArgs.java index 40231b6c3..1f4fda6c9 100644 --- a/api/src/main/java/io/minio/ListObjectsArgs.java +++ b/api/src/main/java/io/minio/ListObjectsArgs.java @@ -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/ListenBucketNotificationArgs.java b/api/src/main/java/io/minio/ListenBucketNotificationArgs.java index a1dc359bc..3240828ed 100644 --- a/api/src/main/java/io/minio/ListenBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/ListenBucketNotificationArgs.java @@ -48,7 +48,7 @@ public static Builder builder() { 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) { diff --git a/api/src/main/java/io/minio/MinioAsyncClient.java b/api/src/main/java/io/minio/MinioAsyncClient.java index f72e52622..c7fa3faf1 100644 --- a/api/src/main/java/io/minio/MinioAsyncClient.java +++ b/api/src/main/java/io/minio/MinioAsyncClient.java @@ -32,15 +32,12 @@ 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.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; @@ -252,7 +249,7 @@ public CompletableFuture getObject(GetObjectArgs args) return executeGetAsync( args, args.getHeaders(), - (args.versionId() != null) ? newMultimap("versionId", args.versionId()) : null) + (args.versionId() != null) ? Utils.newMultimap("versionId", args.versionId()) : null) .thenApply( response -> { return new GetObjectResponse( @@ -274,7 +271,7 @@ private void downloadObject( try { Path filePath = Paths.get(filename); String tempFilename = - filename + "." + S3Escaper.encode(statObjectResponse.etag()) + ".part.minio"; + filename + "." + Utils.encode(statObjectResponse.etag()) + ".part.minio"; Path tempFilePath = Paths.get(tempFilename); if (Files.exists(tempFilePath)) Files.delete(tempFilePath); os = Files.newOutputStream(tempFilePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE); @@ -674,7 +671,8 @@ public CompletableFuture composeObject(ComposeObjectArgs ar CompletableFuture completableFuture = CompletableFuture.supplyAsync( () -> { - Multimap headers = newMultimap(args.extraHeaders()); + Multimap headers = + Utils.newMultimap(args.extraHeaders()); headers.putAll(args.genHeaders()); return headers; }) @@ -706,8 +704,8 @@ public CompletableFuture composeObject(ComposeObjectArgs ar uploadId -> { Multimap ssecHeaders = HashMultimap.create(); if (args.sse() != null - && args.sse() instanceof ServerSideEncryptionCustomerKey) { - ssecHeaders.putAll(newMultimap(args.sse().headers())); + && args.sse() instanceof ServerSideEncryption.CustomerKey) { + ssecHeaders.putAll(Utils.newMultimap(args.sse().headers())); } int partNumber = 0; @@ -733,7 +731,7 @@ public CompletableFuture composeObject(ComposeObjectArgs ar final Multimap headers; try { - headers = newMultimap(src.headers()); + headers = Utils.newMultimap(src.headers()); } catch (InternalException e) { throw new CompletionException(e); } @@ -785,7 +783,7 @@ public CompletableFuture composeObject(ComposeObjectArgs ar } long endBytes = offset + length - 1; - Multimap headersCopy = newMultimap(headers); + Multimap headersCopy = Utils.newMultimap(headers); headersCopy.put( "x-amz-copy-source-range", "bytes=" + offset + "-" + endBytes); @@ -877,7 +875,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 +890,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 +903,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) @@ -933,9 +931,11 @@ public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) checkArgs(args); byte[] body = - (args.method() == Method.PUT || args.method() == Method.POST) ? HttpUtils.EMPTY_BODY : null; + (args.method() == Http.Method.PUT || args.method() == Http.Method.POST) + ? Utils.EMPTY_BODY + : null; - Multimap queryParams = newMultimap(args.extraQueryParams()); + Multimap queryParams = Utils.newMultimap(args.extraQueryParams()); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); String region = null; @@ -959,7 +959,7 @@ public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) createRequest( url, args.method(), - args.extraHeaders() == null ? null : httpHeaders(args.extraHeaders()), + args.extraHeaders() == null ? null : Utils.httpHeaders(args.extraHeaders()), body, 0, creds); @@ -1090,9 +1090,9 @@ public CompletableFuture removeObject(RemoveObjectArgs args) return executeDeleteAsync( args, args.bypassGovernanceMode() - ? newMultimap("x-amz-bypass-governance-retention", "true") + ? Utils.newMultimap("x-amz-bypass-governance-retention", "true") : null, - (args.versionId() != null) ? newMultimap("versionId", args.versionId()) : null) + (args.versionId() != null) ? Utils.newMultimap("versionId", args.versionId()) : null) .thenAccept(response -> response.close()); } @@ -1105,35 +1105,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 +1148,7 @@ private synchronized void populate() { } try { - List objectList = new LinkedList<>(); + List objectList = new LinkedList<>(); while (objectIter.hasNext() && objectList.size() < 1000) { objectList.add(objectIter.next()); } @@ -1171,8 +1172,8 @@ private synchronized void populate() { } 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; } @@ -1205,11 +1206,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; } @@ -1262,7 +1263,7 @@ public CompletableFuture restoreObject(RestoreObjectArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePostAsync(args, null, newMultimap("restore", ""), args.request()) + return executePostAsync(args, null, Utils.newMultimap("restore", ""), args.request()) .thenAccept(response -> response.close()); } @@ -1325,10 +1326,11 @@ public Iterable> listObjects(ListObjectsArgs 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. + * @return {@link CompletableFuture}<{@link List}<{@link + * ListAllMyBucketsResult.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. @@ -1336,7 +1338,7 @@ public Iterable> listObjects(ListObjectsArgs args) { * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. * @throws XmlParserException thrown to indicate XML parsing error. */ - public CompletableFuture> listBuckets() + public CompletableFuture> listBuckets() throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { return listBucketsAsync(null, null, null, null, null, null) @@ -1350,30 +1352,31 @@ 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 = new LinkedList().iterator(); try { ListBucketsResponse response = listBucketsAsync( @@ -1430,7 +1433,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 +1451,7 @@ public Result next() { return this.error; } - Bucket item = null; + ListAllMyBucketsResult.Bucket item = null; if (this.iterator.hasNext()) { item = this.iterator.next(); } @@ -1576,15 +1579,15 @@ public CompletableFuture makeBucket(MakeBucketArgs args) } Multimap headers = - args.objectLock() ? newMultimap("x-amz-bucket-object-lock-enabled", "true") : null; + args.objectLock() ? Utils.newMultimap("x-amz-bucket-object-lock-enabled", "true") : null; final String location = region; return executeAsync( - Method.PUT, + Http.Method.PUT, args.bucket(), null, location, - httpHeaders(merge(args.extraHeaders(), headers)), + Utils.httpHeaders(Utils.mergeMultimap(args.extraHeaders(), headers)), args.extraQueryParams(), location.equals(US_EAST_1) ? null : new CreateBucketConfiguration(location), 0) @@ -1616,7 +1619,7 @@ public CompletableFuture setBucketVersioning(SetBucketVersioningArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("versioning", ""), args.config(), 0) + return executePutAsync(args, null, Utils.newMultimap("versioning", ""), args.config(), 0) .thenAccept(response -> response.close()); } @@ -1643,7 +1646,7 @@ public CompletableFuture getBucketVersioning( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("versioning", "")) + return executeGetAsync(args, null, Utils.newMultimap("versioning", "")) .thenApply( response -> { try { @@ -1679,7 +1682,7 @@ public CompletableFuture setObjectLockConfiguration(SetObjectLockConfigura throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("object-lock", ""), args.config(), 0) + return executePutAsync(args, null, Utils.newMultimap("object-lock", ""), args.config(), 0) .thenAccept(response -> response.close()); } @@ -1706,7 +1709,7 @@ public CompletableFuture deleteObjectLockConfiguration( NoSuchAlgorithmException, XmlParserException { checkArgs(args); return executePutAsync( - args, null, newMultimap("object-lock", ""), new ObjectLockConfiguration(), 0) + args, null, Utils.newMultimap("object-lock", ""), new ObjectLockConfiguration(), 0) .thenAccept(response -> response.close()); } @@ -1733,7 +1736,7 @@ public CompletableFuture getObjectLockConfiguration( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("object-lock", "")) + return executeGetAsync(args, null, Utils.newMultimap("object-lock", "")) .thenApply( response -> { try { @@ -1774,12 +1777,12 @@ public CompletableFuture setObjectRetention(SetObjectRetentionArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("retention", ""); + Multimap queryParams = Utils.newMultimap("retention", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executePutAsync( args, args.bypassGovernanceMode() - ? newMultimap("x-amz-bypass-governance-retention", "True") + ? Utils.newMultimap("x-amz-bypass-governance-retention", "True") : null, queryParams, args.config(), @@ -1812,7 +1815,7 @@ public CompletableFuture getObjectRetention(GetObjectRetentionArgs ar throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("retention", ""); + Multimap queryParams = Utils.newMultimap("retention", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .exceptionally( @@ -1875,7 +1878,7 @@ public CompletableFuture enableObjectLegalHold(EnableObjectLegalHoldArgs a throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("legal-hold", ""); + Multimap queryParams = Utils.newMultimap("legal-hold", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executePutAsync(args, null, queryParams, new LegalHold(true), 0) .thenAccept(response -> response.close()); @@ -1906,7 +1909,7 @@ public CompletableFuture disableObjectLegalHold(DisableObjectLegalHoldArgs throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("legal-hold", ""); + Multimap queryParams = Utils.newMultimap("legal-hold", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executePutAsync(args, null, queryParams, new LegalHold(false), 0) .thenAccept(response -> response.close()); @@ -1938,7 +1941,7 @@ public CompletableFuture isObjectLegalHoldEnabled(IsObjectLegalHoldEnab throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("legal-hold", ""); + Multimap queryParams = Utils.newMultimap("legal-hold", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .exceptionally( @@ -2158,7 +2161,7 @@ public CompletableFuture getBucketPolicy(GetBucketPolicyArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("policy", "")) + return executeGetAsync(args, null, Utils.newMultimap("policy", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2264,8 +2267,8 @@ public CompletableFuture setBucketPolicy(SetBucketPolicyArgs args) checkArgs(args); return executePutAsync( args, - newMultimap("Content-Type", "application/json"), - newMultimap("policy", ""), + Utils.newMultimap("Content-Type", "application/json"), + Utils.newMultimap("policy", ""), args.config(), 0) .thenAccept(response -> response.close()); @@ -2293,7 +2296,7 @@ public CompletableFuture deleteBucketPolicy(DeleteBucketPolicyArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("policy", "")) + return executeDeleteAsync(args, null, Utils.newMultimap("policy", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2355,7 +2358,7 @@ public CompletableFuture setBucketLifecycle(SetBucketLifecycleArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("lifecycle", ""), args.config(), 0) + return executePutAsync(args, null, Utils.newMultimap("lifecycle", ""), args.config(), 0) .thenAccept(response -> response.close()); } @@ -2380,7 +2383,7 @@ public CompletableFuture deleteBucketLifecycle(DeleteBucketLifecycleArgs a throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("lifecycle", "")) + return executeDeleteAsync(args, null, Utils.newMultimap("lifecycle", "")) .thenAccept(response -> response.close()); } @@ -2407,7 +2410,7 @@ public CompletableFuture getBucketLifecycle(GetBucketLif throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("lifecycle", "")) + return executeGetAsync(args, null, Utils.newMultimap("lifecycle", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2466,7 +2469,7 @@ public CompletableFuture getBucketNotification( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("notification", "")) + return executeGetAsync(args, null, Utils.newMultimap("notification", "")) .thenApply( response -> { try { @@ -2516,7 +2519,7 @@ public CompletableFuture setBucketNotification(SetBucketNotificationArgs a throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("notification", ""), args.config(), 0) + return executePutAsync(args, null, Utils.newMultimap("notification", ""), args.config(), 0) .thenAccept(response -> response.close()); } @@ -2542,7 +2545,11 @@ public CompletableFuture deleteBucketNotification(DeleteBucketNotification NoSuchAlgorithmException, XmlParserException { checkArgs(args); return executePutAsync( - args, null, newMultimap("notification", ""), new NotificationConfiguration(), 0) + args, + null, + Utils.newMultimap("notification", ""), + new NotificationConfiguration(null, null, null, null), + 0) .thenAccept(response -> response.close()); } @@ -2569,7 +2576,7 @@ public CompletableFuture getBucketReplication( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("replication", "")) + return executeGetAsync(args, null, Utils.newMultimap("replication", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2652,9 +2659,9 @@ public CompletableFuture setBucketReplication(SetBucketReplicationArgs arg return executePutAsync( args, (args.objectLockToken() != null) - ? newMultimap("x-amz-bucket-object-lock-token", args.objectLockToken()) + ? Utils.newMultimap("x-amz-bucket-object-lock-token", args.objectLockToken()) : null, - newMultimap("replication", ""), + Utils.newMultimap("replication", ""), args.config(), 0) .thenAccept(response -> response.close()); @@ -2681,7 +2688,7 @@ public CompletableFuture deleteBucketReplication(DeleteBucketReplicationAr throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("replication", "")) + return executeDeleteAsync(args, null, Utils.newMultimap("replication", "")) .thenAccept(response -> response.close()); } @@ -2732,7 +2739,7 @@ public CloseableIterator> listenBucketNotification( checkArgs(args); Multimap queryParams = - newMultimap("prefix", args.prefix(), "suffix", args.suffix()); + Utils.newMultimap("prefix", args.prefix(), "suffix", args.suffix()); for (String event : args.events()) { queryParams.put("events", event); } @@ -2805,8 +2812,8 @@ public SelectResponseStream selectObjectContent(SelectObjectContentArgs args) response = executePostAsync( args, - (args.ssec() != null) ? newMultimap(args.ssec().headers()) : null, - newMultimap("select", "", "select-type", "2"), + (args.ssec() != null) ? Utils.newMultimap(args.ssec().headers()) : null, + Utils.newMultimap("select", "", "select-type", "2"), new SelectObjectContentRequest( args.sqlExpression(), args.requestProgress(), @@ -2844,7 +2851,7 @@ public CompletableFuture setBucketEncryption(SetBucketEncryptionArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("encryption", ""), args.config(), 0) + return executePutAsync(args, null, Utils.newMultimap("encryption", ""), args.config(), 0) .thenAccept(response -> response.close()); } @@ -2870,7 +2877,7 @@ public CompletableFuture getBucketEncryption(GetBucketEncrypti throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("encryption", "")) + return executeGetAsync(args, null, Utils.newMultimap("encryption", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2927,7 +2934,7 @@ public CompletableFuture deleteBucketEncryption(DeleteBucketEncryptionArgs throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("encryption", "")) + return executeDeleteAsync(args, null, Utils.newMultimap("encryption", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -2977,7 +2984,7 @@ public CompletableFuture getBucketTags(GetBucketTagsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("tagging", "")) + return executeGetAsync(args, null, Utils.newMultimap("tagging", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -3034,7 +3041,7 @@ public CompletableFuture setBucketTags(SetBucketTagsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("tagging", ""), args.tags(), 0) + return executePutAsync(args, null, Utils.newMultimap("tagging", ""), args.tags(), 0) .thenAccept(response -> response.close()); } @@ -3059,7 +3066,7 @@ public CompletableFuture deleteBucketTags(DeleteBucketTagsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("tagging", "")) + return executeDeleteAsync(args, null, Utils.newMultimap("tagging", "")) .thenAccept(response -> response.close()); } @@ -3085,7 +3092,7 @@ public CompletableFuture getObjectTags(GetObjectTagsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("tagging", ""); + Multimap queryParams = Utils.newMultimap("tagging", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .thenApply( @@ -3128,7 +3135,7 @@ public CompletableFuture setObjectTags(SetObjectTagsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("tagging", ""); + Multimap queryParams = Utils.newMultimap("tagging", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executePutAsync(args, null, queryParams, args.tags(), 0) .thenAccept(response -> response.close()); @@ -3155,7 +3162,7 @@ public CompletableFuture deleteObjectTags(DeleteObjectTagsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("tagging", ""); + Multimap queryParams = Utils.newMultimap("tagging", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeDeleteAsync(args, null, queryParams).thenAccept(response -> response.close()); } @@ -3181,7 +3188,7 @@ public CompletableFuture getBucketCors(GetBucketCorsArgs args throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeGetAsync(args, null, newMultimap("cors", "")) + return executeGetAsync(args, null, Utils.newMultimap("cors", "")) .exceptionally( e -> { Throwable ex = e.getCause(); @@ -3258,7 +3265,7 @@ public CompletableFuture setBucketCors(SetBucketCorsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executePutAsync(args, null, newMultimap("cors", ""), args.config(), 0) + return executePutAsync(args, null, Utils.newMultimap("cors", ""), args.config(), 0) .thenAccept(response -> response.close()); } @@ -3283,7 +3290,7 @@ public CompletableFuture deleteBucketCors(DeleteBucketCorsArgs args) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - return executeDeleteAsync(args, null, newMultimap("cors", "")) + return executeDeleteAsync(args, null, Utils.newMultimap("cors", "")) .thenAccept(response -> response.close()); } @@ -3309,7 +3316,7 @@ public CompletableFuture getObjectAcl(GetObjectAclArgs args throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("acl", ""); + Multimap queryParams = Utils.newMultimap("acl", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); return executeGetAsync(args, null, queryParams) .thenApply( @@ -3355,7 +3362,7 @@ public CompletableFuture getObjectAttributes( NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("attributes", ""); + Multimap queryParams = Utils.newMultimap("attributes", ""); if (args.versionId() != null) queryParams.put("versionId", args.versionId()); Multimap headers = HashMultimap.create(); @@ -3494,7 +3501,7 @@ public CompletableFuture uploadSnowballObjects( }) .thenCompose( baos -> { - Multimap headers = newMultimap(args.extraHeaders()); + Multimap headers = Utils.newMultimap(args.extraHeaders()); headers.putAll(args.genHeaders()); headers.put("X-Amz-Meta-Snowball-Auto-Extract", "true"); @@ -3617,7 +3624,7 @@ public CompletableFuture putObjectFanOut(PutObjectFanOu multipartBuilder.addFormDataPart( "file", "fanout-content", - new HttpRequestBody(new PartSource(args.stream(), args.size()), null)); + new Http.RequestBody(args.stream(), args.size(), Utils.DEFAULT_MEDIA_TYPE)); return multipartBuilder.build(); } catch (JsonProcessingException e) { @@ -3684,9 +3691,11 @@ public CompletableFuture promptObject(PromptObjectArgs arg NoSuchAlgorithmException, XmlParserException { checkArgs(args); - Multimap queryParams = newMultimap("lambdaArn", args.lambdaArn()); + Multimap queryParams = Utils.newMultimap("lambdaArn", args.lambdaArn()); Multimap headers = - merge(newMultimap(args.headers()), newMultimap("Content-Type", "application/json")); + Utils.mergeMultimap( + Utils.newMultimap(args.headers()), + Utils.newMultimap("Content-Type", "application/json")); Map promptArgs = args.promptArgs(); if (promptArgs == null) promptArgs = new HashMap<>(); @@ -3727,21 +3736,21 @@ private void setAwsInfo(String host, boolean https) { this.awsDomainSuffix = null; this.awsDualstack = false; - if (!HttpUtils.HOSTNAME_REGEX.matcher(host).find()) return; + if (!Utils.HOSTNAME_REGEX.matcher(host).find()) return; - if (HttpUtils.AWS_ELB_ENDPOINT_REGEX.matcher(host).find()) { + 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 (!HttpUtils.AWS_ENDPOINT_REGEX.matcher(host).find()) return; + if (!Utils.AWS_ENDPOINT_REGEX.matcher(host).find()) return; - if (!HttpUtils.AWS_S3_ENDPOINT_REGEX.matcher(host).find()) { + if (!Utils.AWS_S3_ENDPOINT_REGEX.matcher(host).find()) { throw new IllegalArgumentException("invalid Amazon AWS host " + host); } - Matcher matcher = HttpUtils.AWS_S3_PREFIX_REGEX.matcher(host); + Matcher matcher = Utils.AWS_S3_PREFIX_REGEX.matcher(host); matcher.lookingAt(); int end = matcher.end(); @@ -3776,12 +3785,12 @@ private void setBaseUrl(HttpUrl url) { } public Builder endpoint(String endpoint) { - setBaseUrl(HttpUtils.getBaseUrl(endpoint)); + setBaseUrl(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"); } @@ -3792,19 +3801,19 @@ public Builder endpoint(String endpoint, int port, boolean secure) { } public Builder endpoint(URL url) { - HttpUtils.validateNotNull(url, "url"); + Utils.validateNotNull(url, "url"); return endpoint(HttpUrl.get(url)); } public Builder endpoint(HttpUrl url) { - HttpUtils.validateNotNull(url, "url"); - HttpUtils.validateUrl(url); + Utils.validateNotNull(url, "url"); + Utils.validateUrl(url); setBaseUrl(url); return this; } public Builder region(String region) { - if (region != null && !HttpUtils.REGION_REGEX.matcher(region).find()) { + if (region != null && !Utils.REGION_REGEX.matcher(region).find()) { throw new IllegalArgumentException("invalid region " + region); } this.region = region; @@ -3822,20 +3831,20 @@ public Builder credentialsProvider(Provider provider) { } public Builder httpClient(OkHttpClient httpClient) { - HttpUtils.validateNotNull(httpClient, "http client"); + Utils.validateNotNull(httpClient, "http client"); this.httpClient = httpClient; return this; } public Builder httpClient(OkHttpClient httpClient, boolean close) { - HttpUtils.validateNotNull(httpClient, "http client"); + Utils.validateNotNull(httpClient, "http client"); this.httpClient = httpClient; this.closeHttpClient = close; return this; } public MinioAsyncClient build() { - HttpUtils.validateNotNull(this.baseUrl, "endpoint"); + Utils.validateNotNull(this.baseUrl, "endpoint"); if (this.awsDomainSuffix != null && this.awsDomainSuffix.endsWith(".cn") @@ -3847,9 +3856,7 @@ public MinioAsyncClient build() { if (this.httpClient == null) { this.closeHttpClient = true; - this.httpClient = - HttpUtils.newDefaultHttpClient( - DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); + this.httpClient = Http.newDefaultClient(); } return new MinioAsyncClient( diff --git a/api/src/main/java/io/minio/MinioClient.java b/api/src/main/java/io/minio/MinioClient.java index 3b2bf5e19..f38afc69b 100644 --- a/api/src/main/java/io/minio/MinioClient.java +++ b/api/src/main/java/io/minio/MinioClient.java @@ -17,7 +17,6 @@ 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; @@ -27,11 +26,11 @@ import io.minio.errors.ServerException; import io.minio.errors.XmlParserException; 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; @@ -461,7 +460,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 +475,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 +488,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) @@ -641,20 +640,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); } @@ -755,13 +755,13 @@ 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. + * @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. @@ -772,7 +772,7 @@ public Iterable> listObjects(ListObjectsArgs args) { * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. * @throws XmlParserException thrown to indicate XML parsing error. */ - public List listBuckets() + public List listBuckets() throws ErrorResponseException, InsufficientDataException, InternalException, InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, ServerException, XmlParserException { @@ -790,16 +790,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); } @@ -2624,7 +2625,9 @@ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) * @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.") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SIC", + justification = "Should not be used in production anyways.") public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmException { asyncClient.ignoreCertCheck(); } @@ -2660,26 +2663,6 @@ public void traceOff() throws IOException { 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..854d85f0b 100644 --- a/api/src/main/java/io/minio/ObjectArgs.java +++ b/api/src/main/java/io/minio/ObjectArgs.java @@ -30,7 +30,7 @@ public String object() { 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..51b098aad 100644 --- a/api/src/main/java/io/minio/ObjectConditionalReadArgs.java +++ b/api/src/main/java/io/minio/ObjectConditionalReadArgs.java @@ -92,9 +92,9 @@ public Multimap getHeaders() { public Multimap genCopyHeaders() { Multimap headers = HashMultimap.create(); - String copySource = S3Escaper.encodePath("/" + bucketName + "/" + objectName); + 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); @@ -147,13 +147,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; } diff --git a/api/src/main/java/io/minio/ObjectReadArgs.java b/api/src/main/java/io/minio/ObjectReadArgs.java index 2c36048f1..0bfab6ab3 100644 --- a/api/src/main/java/io/minio/ObjectReadArgs.java +++ b/api/src/main/java/io/minio/ObjectReadArgs.java @@ -21,9 +21,9 @@ /** Base argument class for reading object. */ public abstract class ObjectReadArgs extends ObjectVersionArgs { - protected ServerSideEncryptionCustomerKey ssec; + protected ServerSideEncryption.CustomerKey ssec; - public ServerSideEncryptionCustomerKey ssec() { + public ServerSideEncryption.CustomerKey ssec() { return ssec; } @@ -35,7 +35,7 @@ protected void validateSsec(HttpUrl url) { 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/ObjectWriteArgs.java b/api/src/main/java/io/minio/ObjectWriteArgs.java index b7d76613b..0f06bf743 100644 --- a/api/src/main/java/io/minio/ObjectWriteArgs.java +++ b/api/src/main/java/io/minio/ObjectWriteArgs.java @@ -82,7 +82,7 @@ public Multimap genHeaders() { 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); @@ -92,7 +92,7 @@ public Multimap genHeaders() { headers.put("x-amz-object-lock-mode", retention.mode().name()); headers.put( "x-amz-object-lock-retain-until-date", - retention.retainUntilDate().format(Time.RESPONSE_DATE_FORMAT)); + retention.retainUntilDate().format(Time.ISO8601UTC_FORMAT)); } if (legalHold) { @@ -111,13 +111,13 @@ protected void validateSse(HttpUrl url) { public abstract static class Builder, A extends ObjectWriteArgs> extends ObjectArgs.Builder { public B headers(Map headers) { - final Multimap headersCopy = toMultimap(headers); + final Multimap headersCopy = Utils.newMultimap(headers); operations.add(args -> args.headers = headersCopy); return (B) this; } public B headers(Multimap headers) { - final Multimap headersCopy = copyMultimap(headers); + final Multimap headersCopy = Utils.newMultimap(headers); operations.add(args -> args.headers = headersCopy); return (B) this; } diff --git a/api/src/main/java/io/minio/PartReader.java b/api/src/main/java/io/minio/PartReader.java index 9209c4536..f8f1d9c5f 100644 --- a/api/src/main/java/io/minio/PartReader.java +++ b/api/src/main/java/io/minio/PartReader.java @@ -17,14 +17,16 @@ package io.minio; -import com.google.common.io.BaseEncoding; 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.HashMap; +import java.util.Map; import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; /** PartReader reads part data from file or input stream sequentially and returns PartSource. */ @@ -42,12 +44,14 @@ class PartReader { private int partNumber; private long totalDataRead; + private Map hashers; private ByteBufferStream[] buffers; private byte[] oneByte = null; boolean eof; - private PartReader(long objectSize, long partSize, int partCount) { + private PartReader(long objectSize, long partSize, int partCount, Checksum.Algorithm[] algorithms) + throws NoSuchAlgorithmException { this.objectSize = objectSize; this.partSize = partSize; this.partCount = partCount; @@ -57,27 +61,71 @@ private PartReader(long objectSize, long partSize, int partCount) { if (bufferCount == 0) bufferCount++; this.buffers = new ByteBufferStream[(int) bufferCount]; + + if (algorithms != null) { + for (Checksum.Algorithm algorithm : algorithms) { + if (algorithm != null) { + if (this.hashers == null) this.hashers = new HashMap<>(); + this.hashers.put(algorithm, algorithm.hasher()); + } + } + } } - 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 NoSuchAlgorithmException { + this(objectSize, partSize, partCount, algorithms); this.file = Objects.requireNonNull(file, "file must not be null"); if (this.objectSize < 0) throw new IllegalArgumentException("object size must be provided"); } - 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 NoSuchAlgorithmException { + this(objectSize, partSize, partCount, algorithms); this.stream = Objects.requireNonNull(stream, "stream must not be null"); for (int i = 0; i < this.buffers.length; i++) this.buffers[i] = new ByteBufferStream(); } - private long readStreamChunk(ByteBufferStream buffer, long size, MessageDigest sha256) - throws IOException { + private void updateHashers(byte[] data, int off, int len) { + if (this.hashers == null || this.hashers.size() == 0) return; + + if (this.hashers.size() > 1) { + for (Map.Entry entry : this.hashers.entrySet()) { + entry.getValue().update(data, off, len); + } + return; + } + + ExecutorService executor = Executors.newFixedThreadPool(this.hashers.size()); + for (Map.Entry entry : this.hashers.entrySet()) { + if (executor.submit(() -> entry.getValue().update(data, off, len)) == null) { + throw new RuntimeException("this should not happen"); + } + } + executor.shutdown(); + try { + executor.awaitTermination(5, TimeUnit.MINUTES); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private long readStreamChunk(ByteBufferStream buffer, long size) throws IOException { long totalBytesRead = 0; if (this.oneByte != null) { buffer.write(this.oneByte); - sha256.update(this.oneByte); + this.updateHashers(this.oneByte, 0, this.oneByte.length); totalBytesRead++; this.oneByte = null; } @@ -92,14 +140,14 @@ private long readStreamChunk(ByteBufferStream buffer, long size, MessageDigest s throw new IOException("unexpected EOF"); } buffer.write(this.buf16k, 0, bytesRead); - sha256.update(this.buf16k, 0, bytesRead); + this.updateHashers(this.buf16k, 0, bytesRead); totalBytesRead += bytesRead; } return totalBytesRead; } - private long readStream(long size, MessageDigest sha256) throws IOException { + private long readStream(long size) throws IOException { long count = size / CHUNK_SIZE; long lastChunkSize = size - (count * CHUNK_SIZE); if (lastChunkSize > 0) { @@ -112,7 +160,7 @@ private long readStream(long size, MessageDigest sha256) throws IOException { 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); + long bytesRead = this.readStreamChunk(buffers[(int) (i - 1)], chunkSize); totalBytesRead += bytesRead; } @@ -124,7 +172,7 @@ private long readStream(long size, MessageDigest sha256) throws IOException { return totalBytesRead; } - private long readFile(long size, MessageDigest sha256) throws IOException { + private long readFile(long size) throws IOException { long position = this.file.getFilePointer(); long totalBytesRead = 0; @@ -133,7 +181,7 @@ private long readFile(long size, MessageDigest sha256) throws IOException { 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); + this.updateHashers(this.buf16k, 0, bytesRead); totalBytesRead += bytesRead; } @@ -141,8 +189,8 @@ private long readFile(long size, MessageDigest sha256) throws IOException { return totalBytesRead; } - private long read(long size, MessageDigest sha256) throws IOException { - return (this.file != null) ? readFile(size, sha256) : readStream(size, sha256); + private long read(long size) throws IOException { + return (this.file != null) ? readFile(size) : readStream(size); } public PartSource getPart() throws NoSuchAlgorithmException, IOException { @@ -150,21 +198,25 @@ public PartSource getPart() throws NoSuchAlgorithmException, IOException { 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); + long bytesRead = this.read(partSize); this.totalDataRead += bytesRead; if (this.objectSize < 0 && this.eof) this.partCount = this.partNumber; - String sha256Hash = BaseEncoding.base16().encode(sha256.digest()).toLowerCase(Locale.US); + Map checksums = null; + if (this.hashers != null) { + checksums = new HashMap<>(); + for (Map.Entry entry : this.hashers.entrySet()) { + checksums.put(entry.getKey(), entry.getValue().sum()); + } + } if (this.file != null) { - return new PartSource(this.partNumber, this.file, bytesRead, null, sha256Hash); + return new PartSource(this.partNumber, this.file, bytesRead, checksums); } - return new PartSource(this.partNumber, this.buffers, bytesRead, null, sha256Hash); + return new PartSource(this.partNumber, this.buffers, bytesRead, checksums); } public int partCount() { diff --git a/api/src/main/java/io/minio/PartSource.java b/api/src/main/java/io/minio/PartSource.java index b18581eb5..304edbcf3 100644 --- a/api/src/main/java/io/minio/PartSource.java +++ b/api/src/main/java/io/minio/PartSource.java @@ -25,36 +25,34 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; 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 Map checksums; private RandomAccessFile file; private long position; private ByteBufferStream[] buffers; - private InputStream inputStream; - - private PartSource(int partNumber, long size, String md5Hash, String sha256Hash) { + private PartSource(int partNumber, long size, Map checksums) { this.partNumber = partNumber; this.size = size; - this.md5Hash = md5Hash; - this.sha256Hash = sha256Hash; + this.checksums = checksums; } public PartSource( - int partNumber, @Nonnull RandomAccessFile file, long size, String md5Hash, String sha256Hash) + int partNumber, + @Nonnull RandomAccessFile file, + long size, + Map checksums) throws IOException { - this(partNumber, size, md5Hash, sha256Hash); + this(partNumber, size, checksums); this.file = Objects.requireNonNull(file, "file must not be null"); this.position = this.file.getFilePointer(); } @@ -63,17 +61,11 @@ public PartSource( int partNumber, @Nonnull ByteBufferStream[] buffers, long size, - String md5Hash, - String sha256Hash) { - this(partNumber, size, md5Hash, sha256Hash); + Map checksums) { + this(partNumber, size, checksums); 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; } @@ -82,26 +74,18 @@ public long size() { return this.size; } - public String md5Hash() { - return this.md5Hash; + public Map checksums() { + return checksums; } - public String sha256Hash() { - return this.sha256Hash; - } - - public Source source() throws IOException { + public InputStream inputStream() 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); + return Channels.newInputStream(this.file.getChannel()); } InputStream stream = buffers[0].inputStream(); - if (buffers.length == 1) return Okio.source(stream); + if (buffers.length == 1) return stream; List streams = new ArrayList<>(); streams.add(stream); @@ -109,7 +93,7 @@ public Source source() throws IOException { 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))); + if (streams.size() == 1) return stream; + return 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..3e0e2cb53 100644 --- a/api/src/main/java/io/minio/PostPolicy.java +++ b/api/src/main/java/io/minio/PostPolicy.java @@ -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()) { diff --git a/api/src/main/java/io/minio/PromptObjectArgs.java b/api/src/main/java/io/minio/PromptObjectArgs.java index f092f4c65..cc115eb2b 100644 --- a/api/src/main/java/io/minio/PromptObjectArgs.java +++ b/api/src/main/java/io/minio/PromptObjectArgs.java @@ -51,25 +51,25 @@ public static final class Builder extends ObjectArgs.Builder 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/PutObjectArgs.java b/api/src/main/java/io/minio/PutObjectArgs.java index bdc2f5869..5bc806ced 100644 --- a/api/src/main/java/io/minio/PutObjectArgs.java +++ b/api/src/main/java/io/minio/PutObjectArgs.java @@ -47,7 +47,7 @@ public static final class Builder extends PutObjectBaseArgs.BuilderA valid part size is between 5MiB to 5GiB (both limits inclusive). */ public Builder stream(InputStream stream, long objectSize, long partSize) { - validateNotNull(stream, "stream"); + Utils.validateNotNull(stream, "stream"); long[] partinfo = getPartInfo(objectSize, partSize); long pSize = partinfo[0]; diff --git a/api/src/main/java/io/minio/PutObjectBaseArgs.java b/api/src/main/java/io/minio/PutObjectBaseArgs.java index aaec5e1bb..e9fd78532 100644 --- a/api/src/main/java/io/minio/PutObjectBaseArgs.java +++ b/api/src/main/java/io/minio/PutObjectBaseArgs.java @@ -62,7 +62,7 @@ public boolean preloadData() { public abstract static class Builder, A extends PutObjectBaseArgs> extends ObjectWriteArgs.Builder { protected void validateContentType(String contentType) { - validateNotEmptyString(contentType, "content type"); + Utils.validateNotEmptyString(contentType, "content type"); if (MediaType.parse(contentType) == null) { throw new IllegalArgumentException( "invalid content type '" + contentType + "' as per RFC 2045"); diff --git a/api/src/main/java/io/minio/PutObjectFanOutArgs.java b/api/src/main/java/io/minio/PutObjectFanOutArgs.java index 64ad1cb60..c8810dbcd 100644 --- a/api/src/main/java/io/minio/PutObjectFanOutArgs.java +++ b/api/src/main/java/io/minio/PutObjectFanOutArgs.java @@ -87,12 +87,12 @@ public static final class Builder extends BucketArgs.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..6b7e9efca 100644 --- a/api/src/main/java/io/minio/PutObjectFanOutResponse.java +++ b/api/src/main/java/io/minio/PutObjectFanOutResponse.java @@ -17,6 +17,7 @@ package io.minio; import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.ZonedDateTime; import java.util.List; import okhttp3.Headers; @@ -48,8 +49,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 +68,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/RemoveObjectsArgs.java b/api/src/main/java/io/minio/RemoveObjectsArgs.java index a3b678e65..b03e6b94f 100644 --- a/api/src/main/java/io/minio/RemoveObjectsArgs.java +++ b/api/src/main/java/io/minio/RemoveObjectsArgs.java @@ -16,7 +16,7 @@ package io.minio; -import io.minio.messages.DeleteObject; +import io.minio.messages.DeleteRequest; import java.util.LinkedList; import java.util.Objects; @@ -25,13 +25,13 @@ */ 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; } @@ -46,8 +46,8 @@ public Builder bypassGovernanceMode(boolean 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..ae606b7d9 100644 --- a/api/src/main/java/io/minio/RestoreObjectArgs.java +++ b/api/src/main/java/io/minio/RestoreObjectArgs.java @@ -34,7 +34,7 @@ public static Builder builder() { /** Argument 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/S3Base.java b/api/src/main/java/io/minio/S3Base.java index 324637ccb..b78a530eb 100644 --- a/api/src/main/java/io/minio/S3Base.java +++ b/api/src/main/java/io/minio/S3Base.java @@ -23,11 +23,9 @@ 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; @@ -36,14 +34,9 @@ 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; @@ -59,7 +52,6 @@ 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; @@ -87,9 +79,7 @@ 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; @@ -118,7 +108,6 @@ public abstract class S3Base implements AutoCloseable { 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"; @@ -136,7 +125,7 @@ public abstract class S3Base implements AutoCloseable { 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(); + private String userAgent = Utils.getDefaultUserAgent(); protected HttpUrl baseUrl; protected String awsS3Prefix; @@ -148,29 +137,6 @@ public abstract class S3Base implements AutoCloseable { 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, @@ -192,35 +158,6 @@ protected S3Base( 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; @@ -250,39 +187,6 @@ protected void checkArgs(BaseArgs args) { } } - /** 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, @@ -319,7 +223,7 @@ public void throwEncapsulatedException(ExecutionException e) } private String[] handleRedirectResponse( - Method method, String bucketName, Response response, boolean retry) { + Http.Method method, String bucketName, Response response, boolean retry) { String code = null; String message = null; @@ -339,7 +243,7 @@ private String[] handleRedirectResponse( if (retry && region != null - && method.equals(Method.HEAD) + && method.equals(Http.Method.HEAD) && bucketName != null && regionCache.get(bucketName) != null) { code = RETRY_HEAD; @@ -401,7 +305,7 @@ private String buildListBucketsUrl(HttpUrl.Builder builder, String region) { /** Build URL for given parameters. */ protected HttpUrl buildUrl( - Method method, + Http.Method method, String bucketName, String objectName, String region, @@ -416,7 +320,7 @@ protected HttpUrl buildUrl( 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())); } } @@ -428,7 +332,7 @@ protected HttpUrl buildUrl( boolean enforcePathStyle = ( // use path style for make bucket to workaround "AuthorizationHeaderMalformed" error from // s3.amazonaws.com - (method == Method.PUT && objectName == null && queryParamMap == null) + (method == Http.Method.PUT && objectName == null && queryParamMap == null) // use path style for location query || (queryParamMap != null && queryParamMap.containsKey("location")) @@ -442,50 +346,27 @@ protected HttpUrl buildUrl( } if (enforcePathStyle || !this.useVirtualStyle) { - urlBuilder.addEncodedPathSegment(S3Escaper.encode(bucketName)); + urlBuilder.addEncodedPathSegment(Utils.encode(bucketName)); } else { urlBuilder.host(bucketName + "." + host); } if (objectName != null) { - urlBuilder.addEncodedPathSegments(S3Escaper.encodePath(objectName)); + urlBuilder.addEncodedPathSegments(Utils.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) + HttpUrl url, Http.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)); + requestBuilder.header("Host", Utils.getHostHeader(url)); // Disable default gzip compression by okhttp library. requestBuilder.header("Accept-Encoding", "identity"); requestBuilder.header("User-Agent", this.userAgent); @@ -494,27 +375,43 @@ protected Request createRequest( return requestBuilder.method(method.toString(), (RequestBody) body).build(); } - String md5Hash = Digest.ZERO_MD5_HASH; + String md5Hash = Utils.ZERO_MD5_HASH; if (body != null) { - md5Hash = (body instanceof byte[]) ? Digest.md5Hash((byte[]) body, length) : null; + md5Hash = (body instanceof byte[]) ? Utils.md5Hash((byte[]) body, length) : null; } String sha256Hash = null; if (creds != null) { - sha256Hash = Digest.ZERO_SHA256_HASH; + sha256Hash = Utils.ZERO_SHA256_HASH; if (!url.isHttps()) { if (body != null) { if (body instanceof PartSource) { - sha256Hash = ((PartSource) body).sha256Hash(); + PartSource partSource = (PartSource) body; + Map checksums = partSource.checksums(); + if (checksums != null) { + for (Map.Entry entry : checksums.entrySet()) { + if (entry.getKey() == Checksum.Algorithm.SHA256) { + sha256Hash = Checksum.hexString(entry.getValue()); + } + } + } } else if (body instanceof byte[]) { - sha256Hash = Digest.sha256Hash((byte[]) body, length); + sha256Hash = Utils.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(); + PartSource partSource = (PartSource) body; + Map checksums = partSource.checksums(); + if (checksums != null) { + for (Map.Entry entry : checksums.entrySet()) { + if (entry.getKey() == Checksum.Algorithm.SHA256) { + sha256Hash = Checksum.hexString(entry.getValue()); + } + } + } } } } @@ -531,16 +428,13 @@ protected Request createRequest( 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"); - } - + MediaType contentType = Utils.mediaType(headers == null ? null : headers.get("Content-Type")); if (body instanceof PartSource) { - requestBody = new HttpRequestBody((PartSource) body, contentType); + PartSource partSource = (PartSource) body; + requestBody = + new Http.RequestBody(partSource.inputStream(), partSource.size(), contentType); } else { - requestBody = new HttpRequestBody((byte[]) body, length, contentType); + requestBody = new Http.RequestBody((byte[]) body, length, contentType); } } @@ -567,7 +461,7 @@ private StringBuilder newTraceBuilder(Request request, String body) { /** Execute HTTP request asynchronously for given parameters. */ protected CompletableFuture executeAsync( - Method method, + Http.Method method, String bucketName, String objectName, String region, @@ -592,8 +486,8 @@ protected CompletableFuture executeAsync( traceRequestBody = true; } - if (body == null && (method == Method.PUT || method == Method.POST)) { - body = HttpUtils.EMPTY_BODY; + if (body == null && (method == Http.Method.PUT || method == Http.Method.POST)) { + body = Utils.EMPTY_BODY; } HttpUrl url = buildUrl(method, bucketName, objectName, region, queryParamMap); @@ -618,7 +512,7 @@ protected CompletableFuture executeAsync( traceBuilder.append("\n"); OkHttpClient httpClient = this.httpClient; - if (!(body instanceof byte[]) && (method == Method.PUT || method == Method.POST)) { + if (!(body instanceof byte[]) && (method == Http.Method.PUT || method == Http.Method.POST)) { // Issue #924: disable connection retry for PUT and POST methods for other than byte array. httpClient = this.httpClient.newBuilder().retryOnConnectionFailure(false).build(); } @@ -658,7 +552,7 @@ private void onResponse(final Response response) throws IOException { // GetObject/ListenBucketNotification // S3 API. Set keys = queryParamMap.keySet(); - if ((method != Method.GET + if ((method != Http.Method.GET || objectName == null || !Collections.disjoint(keys, TRACE_QUERY_PARAMS)) && !(keys.contains("events") @@ -678,7 +572,7 @@ private void onResponse(final Response response) throws IOException { errorXml = responseBody.string(); } - if (!("".equals(errorXml) && method.equals(Method.HEAD))) { + if (!("".equals(errorXml) && method.equals(Http.Method.HEAD))) { traceBuilder.append(errorXml).append("\n"); if (traceStream != null) traceStream.println(errorXml); } @@ -688,7 +582,7 @@ private void onResponse(final Response response) throws IOException { // 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) + if (!method.equals(Http.Method.HEAD) && (contentType == null || !Arrays.asList(contentType.split(";")).contains("application/xml"))) { if (response.code() == 304 && response.body().contentLength() == 0) { @@ -717,7 +611,7 @@ private void onResponse(final Response response) throws IOException { completableFuture.completeExceptionally(e); return; } - } else if (!method.equals(Method.HEAD)) { + } else if (!method.equals(Http.Method.HEAD)) { completableFuture.completeExceptionally( new InvalidResponseException( response.code(), contentType, errorXml, traceBuilder.toString())); @@ -809,7 +703,7 @@ private void onResponse(final Response response) throws IOException { /** Execute HTTP request asynchronously for given args and parameters. */ protected CompletableFuture executeAsync( - Method method, + Http.Method method, BaseArgs args, Multimap headers, Multimap queryParams, @@ -857,8 +751,8 @@ protected CompletableFuture executeAsync( bucketName, objectName, location, - httpHeaders(merge(extraHeaders, headers)), - merge(extraQueryParams, queryParams), + Utils.httpHeaders(Utils.mergeMultimap(extraHeaders, headers)), + Utils.mergeMultimap(extraQueryParams, queryParams), body, length); } catch (InsufficientDataException @@ -872,74 +766,6 @@ protected CompletableFuture executeAsync( }); } - /** - * 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, @@ -965,7 +791,14 @@ protected CompletableFuture getRegionAsync(String bucketName, String reg // 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); + Http.Method.GET, + bucketName, + null, + US_EAST_1, + null, + Utils.newMultimap("location", null), + null, + 0); return future.thenApply( response -> { String location; @@ -987,53 +820,12 @@ protected CompletableFuture getRegionAsync(String bucketName, String reg }); } - /** - * 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; - } + return executeAsync(Http.Method.GET, args, headers, queryParams, null, 0); } /** Execute asynchronously HEAD HTTP request for given parameters. */ @@ -1041,7 +833,7 @@ 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) + return executeAsync(Http.Method.HEAD, args, headers, queryParams, null, 0) .exceptionally( e -> { if (e instanceof ErrorResponseException) { @@ -1059,7 +851,7 @@ protected CompletableFuture executeHeadAsync( } try { - return executeAsync(Method.HEAD, args, headers, queryParams, null, 0); + return executeAsync(Http.Method.HEAD, args, headers, queryParams, null, 0); } catch (InsufficientDataException | InternalException | InvalidKeyException @@ -1071,33 +863,12 @@ protected CompletableFuture executeHeadAsync( }); } - /** - * 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) + return executeAsync(Http.Method.DELETE, args, headers, queryParams, null, 0) .thenApply( response -> { if (response != null) response.body().close(); @@ -1105,27 +876,6 @@ protected CompletableFuture executeDeleteAsync( }); } - /** - * 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, @@ -1134,31 +884,7 @@ protected CompletableFuture executePostAsync( 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; - } + return executeAsync(Http.Method.POST, args, headers, queryParams, data, 0); } /** Execute asynchronously PUT HTTP request for given parameters. */ @@ -1170,32 +896,7 @@ protected CompletableFuture executePutAsync( 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; - } + return executeAsync(Http.Method.PUT, args, headers, queryParams, data, length); } protected CompletableFuture calculatePartCountAsync(List sources) @@ -1282,96 +983,11 @@ protected CompletableFuture calculatePartCountAsync(List 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 Iterator deleteMarkerIterator; + protected Iterator prefixIterator; protected boolean completed = false; protected ListObjectsResult listObjectsResult; protected String lastObjectName; @@ -1402,8 +1018,8 @@ protected synchronized void populate() { this.prefixIterator = this.listObjectsResult.commonPrefixes().iterator(); } else { this.itemIterator = new LinkedList().iterator(); - this.deleteMarkerIterator = new LinkedList().iterator(); - this.prefixIterator = new LinkedList().iterator(); + this.deleteMarkerIterator = new LinkedList().iterator(); + this.prefixIterator = new LinkedList().iterator(); } } @@ -1622,44 +1238,20 @@ protected void populateResult() }; } - protected PartReader newPartReader(Object data, long objectSize, long partSize, int partCount) { + 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); + return new PartReader((RandomAccessFile) data, objectSize, partSize, partCount, algorithms); } if (data instanceof InputStream) { - return new PartReader((InputStream) data, objectSize, partSize, partCount); + return new PartReader((InputStream) data, objectSize, partSize, partCount, algorithms); } 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; @@ -1748,7 +1340,7 @@ public Result next() { private Multimap getCommonListObjectsQueryParams( String delimiter, String encodingType, Integer maxKeys, String prefix) { Multimap queryParams = - newMultimap( + Utils.newMultimap( "delimiter", (delimiter == null) ? "" : delimiter, "max-keys", @@ -1773,8 +1365,7 @@ private Multimap getCommonListObjectsQueryParams( * @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); } /** @@ -1787,9 +1378,11 @@ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) * @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.") + @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( + value = "SIC", + justification = "Should not be used in production anyways.") public void ignoreCertCheck() throws KeyManagementException, NoSuchAlgorithmException { - this.httpClient = HttpUtils.disableCertCheck(this.httpClient); + this.httpClient = Http.disableCertCheck(this.httpClient); } /** @@ -1801,8 +1394,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(); } /** @@ -1827,26 +1419,6 @@ 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; @@ -1870,7 +1442,7 @@ public void disableVirtualStyleEndpoint() { /** 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()) { + if (!Utils.AWS_S3_PREFIX_REGEX.matcher(awsS3Prefix).find()) { throw new IllegalArgumentException("invalid Amazon AWS S3 domain prefix " + awsS3Prefix); } this.awsS3Prefix = awsS3Prefix; @@ -1885,7 +1457,7 @@ protected CompletableFuture statObjectAsync(StatObjectArgs a return executeHeadAsync( args, args.getHeaders(), - (args.versionId() != null) ? newMultimap("versionId", args.versionId()) : null) + (args.versionId() != null) ? Utils.newMultimap("versionId", args.versionId()) : null) .thenApply( response -> new StatObjectResponse( @@ -1925,12 +1497,12 @@ public CompletableFuture abortMultipartUploadAsync location -> { try { return executeAsync( - Method.DELETE, + Http.Method.DELETE, bucketName, objectName, location, - httpHeaders(extraHeaders), - merge(extraQueryParams, newMultimap(UPLOAD_ID, uploadId)), + Utils.httpHeaders(extraHeaders), + Utils.mergeMultimap(extraQueryParams, Utils.newMultimap(UPLOAD_ID, uploadId)), null, 0); } catch (InsufficientDataException @@ -1953,52 +1525,6 @@ public CompletableFuture abortMultipartUploadAsync }); } - /** - * 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 @@ -2029,18 +1555,18 @@ public CompletableFuture completeMultipartUploadAsync( Multimap extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = newMultimap(extraQueryParams); + Multimap queryParams = Utils.newMultimap(extraQueryParams); queryParams.put(UPLOAD_ID, uploadId); return getRegionAsync(bucketName, region) .thenCompose( location -> { try { return executeAsync( - Method.POST, + Http.Method.POST, bucketName, objectName, location, - httpHeaders(extraHeaders), + Utils.httpHeaders(extraHeaders), queryParams, new CompleteMultipartUpload(parts), 0); @@ -2107,71 +1633,23 @@ public CompletableFuture completeMultipartUploadAsync( /** * Do CompleteMultipartUpload - * S3 API. + * href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html">CreateMultipartUpload + * S3 API asynchronously. * * @param bucketName Name of the bucket. - * @param region Region of the bucket. + * @param region Region name of buckets in S3 service. * @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. + * @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 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( + public CompletableFuture createMultipartUploadAsync( String bucketName, String region, String objectName, @@ -2179,10 +1657,10 @@ public CompletableFuture createMultipartUploadAsy Multimap extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = newMultimap(extraQueryParams); + Multimap queryParams = Utils.newMultimap(extraQueryParams); queryParams.put("uploads", ""); - Multimap headersCopy = newMultimap(headers); + Multimap headersCopy = Utils.newMultimap(headers); // set content type if not set already if (!headersCopy.containsKey("Content-Type")) { headersCopy.put("Content-Type", "application/octet-stream"); @@ -2193,11 +1671,11 @@ public CompletableFuture createMultipartUploadAsy location -> { try { return executeAsync( - Method.POST, + Http.Method.POST, bucketName, objectName, location, - httpHeaders(headersCopy), + Utils.httpHeaders(headersCopy), queryParams, null, 0); @@ -2226,49 +1704,6 @@ public CompletableFuture createMultipartUploadAsy }); } - /** - * 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 @@ -2292,7 +1727,7 @@ protected CreateMultipartUploadResponse createMultipartUpload( protected CompletableFuture deleteObjectsAsync( String bucketName, String region, - List objectList, + List objectList, boolean quiet, boolean bypassGovernanceMode, Multimap extraHeaders, @@ -2306,22 +1741,24 @@ protected CompletableFuture deleteObjectsAsync( } Multimap headers = - merge( + Utils.mergeMultimap( extraHeaders, - bypassGovernanceMode ? newMultimap("x-amz-bypass-governance-retention", "true") : null); + bypassGovernanceMode + ? Utils.newMultimap("x-amz-bypass-governance-retention", "true") + : null); - final List objects = objectList; + final List objects = objectList; return getRegionAsync(bucketName, region) .thenCompose( location -> { try { return executeAsync( - Method.POST, + Http.Method.POST, bucketName, null, location, - httpHeaders(headers), - merge(extraQueryParams, newMultimap("delete", "")), + Utils.httpHeaders(headers), + Utils.mergeMultimap(extraQueryParams, Utils.newMultimap("delete", "")), new DeleteRequest(objects, quiet), 0); } catch (InsufficientDataException @@ -2338,8 +1775,8 @@ protected CompletableFuture deleteObjectsAsync( try { String bodyContent = response.body().string(); try { - if (Xml.validate(DeleteError.class, bodyContent)) { - DeleteError error = Xml.unmarshal(DeleteError.class, bodyContent); + 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(), bucketName, region, result); @@ -2359,60 +1796,6 @@ protected CompletableFuture deleteObjectsAsync( }); } - /** - * 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. @@ -2453,7 +1836,7 @@ protected CompletableFuture listObjectsV2Async( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { Multimap queryParams = - merge( + Utils.mergeMultimap( extraQueryParams, getCommonListObjectsQueryParams(delimiter, encodingType, maxKeys, prefix)); queryParams.put("list-type", "2"); @@ -2467,11 +1850,11 @@ protected CompletableFuture listObjectsV2Async( location -> { try { return executeAsync( - Method.GET, + Http.Method.GET, bucketName, null, location, - httpHeaders(extraHeaders), + Utils.httpHeaders(extraHeaders), queryParams, null, 0); @@ -2498,74 +1881,6 @@ protected CompletableFuture listObjectsV2Async( }); } - /** - * 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. @@ -2600,7 +1915,7 @@ protected CompletableFuture listObjectsV1Async( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { Multimap queryParams = - merge( + Utils.mergeMultimap( extraQueryParams, getCommonListObjectsQueryParams(delimiter, encodingType, maxKeys, prefix)); if (marker != null) queryParams.put("marker", marker); @@ -2610,11 +1925,11 @@ protected CompletableFuture listObjectsV1Async( location -> { try { return executeAsync( - Method.GET, + Http.Method.GET, bucketName, null, location, - httpHeaders(extraHeaders), + Utils.httpHeaders(extraHeaders), queryParams, null, 0); @@ -2641,65 +1956,6 @@ protected CompletableFuture listObjectsV1Async( }); } - /** - * 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 @@ -2737,7 +1993,7 @@ protected CompletableFuture listObjectVersionsAsync( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { Multimap queryParams = - merge( + Utils.mergeMultimap( extraQueryParams, getCommonListObjectsQueryParams(delimiter, encodingType, maxKeys, prefix)); if (keyMarker != null) queryParams.put("key-marker", keyMarker); @@ -2749,11 +2005,11 @@ protected CompletableFuture listObjectVersionsAsync( location -> { try { return executeAsync( - Method.GET, + Http.Method.GET, bucketName, null, location, - httpHeaders(extraHeaders), + Utils.httpHeaders(extraHeaders), queryParams, null, 0); @@ -2781,69 +2037,6 @@ protected CompletableFuture listObjectVersionsAsync( }); } - /** - * 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, @@ -2856,7 +2049,7 @@ private Part[] uploadParts( Multimap ssecHeaders = null; // set encryption headers in the case of SSE-C. - if (args.sse() != null && args.sse() instanceof ServerSideEncryptionCustomerKey) { + if (args.sse() != null && args.sse() instanceof ServerSideEncryption.CustomerKey) { ssecHeaders = Multimaps.forMap(args.sse().headers()); } @@ -2982,7 +2175,7 @@ protected CompletableFuture putObjectAsync( throw new IllegalArgumentException("data must be RandomAccessFile or InputStream"); } - Multimap headers = newMultimap(args.extraHeaders()); + Multimap headers = Utils.newMultimap(args.extraHeaders()); headers.putAll(args.genHeaders()); if (!headers.containsKey("Content-Type")) headers.put("Content-Type", contentType); @@ -3051,11 +2244,11 @@ private CompletableFuture putObjectAsync( location -> { try { return executeAsync( - Method.PUT, + Http.Method.PUT, bucketName, objectName, location, - httpHeaders(headers), + Utils.httpHeaders(headers), extraQueryParams, partSource, 0); @@ -3132,11 +2325,11 @@ protected CompletableFuture putObjectAsync( location -> { try { return executeAsync( - Method.PUT, + Http.Method.PUT, bucketName, objectName, location, - httpHeaders(headers), + Utils.httpHeaders(headers), extraQueryParams, data, (int) length); @@ -3165,51 +2358,6 @@ protected CompletableFuture putObjectAsync( }); } - /** - * 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 @@ -3247,9 +2395,9 @@ public CompletableFuture listMultipartUploadsAsync throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { Multimap queryParams = - merge( + Utils.mergeMultimap( extraQueryParams, - newMultimap( + Utils.newMultimap( "uploads", "", "delimiter", @@ -3267,11 +2415,11 @@ public CompletableFuture listMultipartUploadsAsync location -> { try { return executeAsync( - Method.GET, + Http.Method.GET, bucketName, null, location, - httpHeaders(extraHeaders), + Utils.httpHeaders(extraHeaders), queryParams, null, 0); @@ -3299,69 +2447,6 @@ public CompletableFuture listMultipartUploadsAsync }); } - /** - * 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. @@ -3394,9 +2479,9 @@ public CompletableFuture listPartsAsync( throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { Multimap queryParams = - merge( + Utils.mergeMultimap( extraQueryParams, - newMultimap( + Utils.newMultimap( UPLOAD_ID, uploadId, "max-parts", @@ -3410,11 +2495,11 @@ public CompletableFuture listPartsAsync( location -> { try { return executeAsync( - Method.GET, + Http.Method.GET, bucketName, objectName, location, - httpHeaders(extraHeaders), + Utils.httpHeaders(extraHeaders), queryParams, null, 0); @@ -3442,62 +2527,6 @@ public CompletableFuture listPartsAsync( }); } - /** - * 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. @@ -3534,14 +2563,14 @@ public CompletableFuture uploadPartAsync( location -> { try { return executeAsync( - Method.PUT, + Http.Method.PUT, bucketName, objectName, location, - httpHeaders(extraHeaders), - merge( + Utils.httpHeaders(extraHeaders), + Utils.mergeMultimap( extraQueryParams, - newMultimap( + Utils.newMultimap( "partNumber", Integer.toString(partNumber), UPLOAD_ID, uploadId)), partSource, 0); @@ -3631,14 +2660,14 @@ public CompletableFuture uploadPartAsync( location -> { try { return executeAsync( - Method.PUT, + Http.Method.PUT, bucketName, objectName, location, - httpHeaders(extraHeaders), - merge( + Utils.httpHeaders(extraHeaders), + Utils.mergeMultimap( extraQueryParams, - newMultimap( + Utils.newMultimap( "partNumber", Integer.toString(partNumber), UPLOAD_ID, uploadId)), data, (int) length); @@ -3668,113 +2697,6 @@ public CompletableFuture uploadPartAsync( }); } - /** - * 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 @@ -3810,14 +2732,14 @@ public CompletableFuture uploadPartCopyAsync( location -> { try { return executeAsync( - Method.PUT, + Http.Method.PUT, bucketName, objectName, location, - httpHeaders(headers), - merge( + Utils.httpHeaders(headers), + Utils.mergeMultimap( extraQueryParams, - newMultimap( + Utils.newMultimap( "partNumber", Integer.toString(partNumber), "uploadId", uploadId)), null, 0); @@ -3878,7 +2800,7 @@ protected CompletableFuture listBucketsAsync( Multimap extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException { - Multimap queryParams = newMultimap(extraQueryParams); + Multimap queryParams = Utils.newMultimap(extraQueryParams); if (bucketRegion != null) queryParams.put("bucket-region", bucketRegion); if (maxBuckets != null) queryParams.put("max-buckets", Integer.toString(maxBuckets > 0 ? maxBuckets : 10000)); 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..b756d8811 100644 --- a/api/src/main/java/io/minio/SelectObjectContentArgs.java +++ b/api/src/main/java/io/minio/SelectObjectContentArgs.java @@ -65,7 +65,7 @@ public static Builder builder() { 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..28befbd01 100644 --- a/api/src/main/java/io/minio/ServerSideEncryption.java +++ b/api/src/main/java/io/minio/ServerSideEncryption.java @@ -16,9 +16,20 @@ package io.minio; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.io.BaseEncoding; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.HashMap; 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); @@ -31,4 +42,131 @@ public boolean tlsRequired() { public Map copySourceHeaders() { return emptyHeaders; } + + /** S3 type of Server-side encryption. */ + public static class S3 extends ServerSideEncryption { + private static final Map headers; + + static { + Map map = new HashMap<>(); + map.put("X-Amz-Server-Side-Encryption", "AES256"); + headers = Utils.unmodifiableMap(map); + } + + @Override + public final Map 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 Map headers; + + public KMS(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"; + } + } + + /** Customer-key type of Server-side encryption. */ + public static class CustomerKey extends ServerSideEncryption { + private boolean isDestroyed = false; + private final SecretKey secretKey; + private final Map headers; + private final Map copySourceHeaders; + + public CustomerKey(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/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/ServerSideEncryptionS3.java b/api/src/main/java/io/minio/ServerSideEncryptionS3.java deleted file mode 100644 index 4a2615ee7..000000000 --- a/api/src/main/java/io/minio/ServerSideEncryptionS3.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; - -import java.util.HashMap; -import java.util.Map; - -/** 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); - } - - @Override - public final Map headers() { - return headers; - } - - @Override - public final boolean tlsRequired() { - return false; - } - - @Override - public String toString() { - return "SSE-S3"; - } -} diff --git a/api/src/main/java/io/minio/SetBucketCorsArgs.java b/api/src/main/java/io/minio/SetBucketCorsArgs.java index 11d6b59ee..7a297d25e 100644 --- a/api/src/main/java/io/minio/SetBucketCorsArgs.java +++ b/api/src/main/java/io/minio/SetBucketCorsArgs.java @@ -36,7 +36,7 @@ public static Builder builder() { /** Argument 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..d2284bc61 100644 --- a/api/src/main/java/io/minio/SetBucketEncryptionArgs.java +++ b/api/src/main/java/io/minio/SetBucketEncryptionArgs.java @@ -37,7 +37,7 @@ public static Builder builder() { /** Argument 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..a22e89ed9 100644 --- a/api/src/main/java/io/minio/SetBucketLifecycleArgs.java +++ b/api/src/main/java/io/minio/SetBucketLifecycleArgs.java @@ -37,7 +37,7 @@ public static Builder builder() { /** Argument 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..80d583801 100644 --- a/api/src/main/java/io/minio/SetBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/SetBucketNotificationArgs.java @@ -37,7 +37,7 @@ public static Builder builder() { /** Argument 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..a02ee7b80 100644 --- a/api/src/main/java/io/minio/SetBucketPolicyArgs.java +++ b/api/src/main/java/io/minio/SetBucketPolicyArgs.java @@ -36,7 +36,7 @@ public static Builder builder() { /** Argument 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..eb5cbd133 100644 --- a/api/src/main/java/io/minio/SetBucketReplicationArgs.java +++ b/api/src/main/java/io/minio/SetBucketReplicationArgs.java @@ -42,11 +42,11 @@ public static Builder builder() { /** Argument 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..ce6d54b29 100644 --- a/api/src/main/java/io/minio/SetBucketTagsArgs.java +++ b/api/src/main/java/io/minio/SetBucketTagsArgs.java @@ -37,7 +37,7 @@ public static Builder builder() { /** Argument 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 +46,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..02beb5a39 100644 --- a/api/src/main/java/io/minio/SetBucketVersioningArgs.java +++ b/api/src/main/java/io/minio/SetBucketVersioningArgs.java @@ -37,7 +37,7 @@ public static Builder builder() { /** Argument 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..5fbe5d535 100644 --- a/api/src/main/java/io/minio/SetObjectLockConfigurationArgs.java +++ b/api/src/main/java/io/minio/SetObjectLockConfigurationArgs.java @@ -38,7 +38,7 @@ public static Builder builder() { 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..492fb4056 100644 --- a/api/src/main/java/io/minio/SetObjectRetentionArgs.java +++ b/api/src/main/java/io/minio/SetObjectRetentionArgs.java @@ -43,7 +43,7 @@ public static Builder builder() { 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..edcd72acb 100644 --- a/api/src/main/java/io/minio/SetObjectTagsArgs.java +++ b/api/src/main/java/io/minio/SetObjectTagsArgs.java @@ -37,7 +37,7 @@ public static Builder builder() { /** Argument 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 +46,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..b5d5ff9c0 100644 --- a/api/src/main/java/io/minio/Signer.java +++ b/api/src/main/java/io/minio/Signer.java @@ -200,7 +200,7 @@ private void setCanonicalRequest() throws NoSuchAlgorithmException { + "\n" + this.contentSha256; - this.canonicalRequestHash = Digest.sha256Hash(this.canonicalRequest); + this.canonicalRequestHash = Utils.sha256Hash(this.canonicalRequest); } private void setStringToSign() { @@ -224,7 +224,7 @@ private void setChunkStringToSign() throws NoSuchAlgorithmException { + "\n" + this.prevSignature + "\n" - + Digest.sha256Hash("") + + Utils.sha256Hash("") + "\n" + this.contentSha256; } @@ -318,15 +318,15 @@ private void setPresignCanonicalRequest(int expires) throws NoSuchAlgorithmExcep 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("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 +344,7 @@ private void setPresignCanonicalRequest(int expires) throws NoSuchAlgorithmExcep + "\n" + this.contentSha256; - this.canonicalRequestHash = Digest.sha256Hash(this.canonicalRequest); + this.canonicalRequestHash = Utils.sha256Hash(this.canonicalRequest); } /** @@ -367,8 +367,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(); } diff --git a/api/src/main/java/io/minio/StatObjectResponse.java b/api/src/main/java/io/minio/StatObjectResponse.java index 85cf8fe1e..bfb7ee45d 100644 --- a/api/src/main/java/io/minio/StatObjectResponse.java +++ b/api/src/main/java/io/minio/StatObjectResponse.java @@ -17,7 +17,6 @@ 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; @@ -54,7 +53,7 @@ public StatObjectResponse(Headers headers, String bucket, String region, String value = headers.get("x-amz-object-lock-retain-until-date"); this.retentionRetainUntilDate = - (value != null ? ResponseDate.fromString(value).zonedDateTime() : null); + value == null ? null : Time.S3Time.fromString(value).toZonedDateTime(); this.legalHold = new LegalHold("ON".equals(headers.get("x-amz-object-lock-legal-hold"))); 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..70f502b9d 100644 --- a/api/src/main/java/io/minio/UploadObjectArgs.java +++ b/api/src/main/java/io/minio/UploadObjectArgs.java @@ -58,7 +58,7 @@ 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"); } diff --git a/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java b/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java index 25b13751d..136fb204d 100644 --- a/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java +++ b/api/src/main/java/io/minio/UploadSnowballObjectsArgs.java @@ -51,7 +51,7 @@ public static Builder builder() { 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..ddc015fe6 100644 --- a/api/src/main/java/io/minio/Utils.java +++ b/api/src/main/java/io/minio/Utils.java @@ -16,19 +16,169 @@ package io.minio; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.escape.Escaper; +import com.google.common.io.BaseEncoding; +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.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; +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 java.util.stream.Collectors; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.MediaType; /** Collection of utility functions. */ public class Utils { + public static final MediaType DEFAULT_MEDIA_TYPE = MediaType.parse("application/octet-stream"); + + private static final Escaper ESCAPER = UrlEscapers.urlPathSegmentEscaper(); + + // 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 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 +196,663 @@ 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(); + } + + /** Merge two Multimaps. */ + public static Multimap mergeMultimap( + 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. */ + public static 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. */ + public static Multimap newMultimap(Map map) { + return (map != null) ? Multimaps.forMap(map) : HashMultimap.create(); + } + + /** Create new HashMultimap with copy of Multimap. */ + public static Multimap newMultimap(Multimap map) { + return (map != null) ? HashMultimap.create(map) : HashMultimap.create(); + } + + /** Convert Multimap to Headers. */ + public static 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(); + } + + /** 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(); + } + + /** 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); + } + + 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..6e93387b9 100644 --- a/api/src/main/java/io/minio/credentials/AssumeRoleProvider.java +++ b/api/src/main/java/io/minio/credentials/AssumeRoleProvider.java @@ -16,9 +16,9 @@ package io.minio.credentials; -import io.minio.Digest; import io.minio.Signer; import io.minio.Time; +import io.minio.Utils; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.ProviderException; @@ -95,7 +95,7 @@ public AssumeRoleProvider( } String data = urlBuilder.build().encodedQuery(); - this.contentSha256 = Digest.sha256Hash(data); + this.contentSha256 = Utils.sha256Hash(data); this.request = new Request.Builder() .url(url) diff --git a/api/src/main/java/io/minio/credentials/Credentials.java b/api/src/main/java/io/minio/credentials/Credentials.java index fb28da816..00d20bd48 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; @@ -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,15 @@ public String sessionToken() { return sessionToken; } + public ZonedDateTime expiration() { + return expiration == null ? null : expiration.toZonedDateTime(); + } + public boolean isExpired() { if (expiration == null) { return false; } - return ZonedDateTime.now().plus(Duration.ofSeconds(10)).isAfter(expiration.zonedDateTime()); + return ZonedDateTime.now().plus(Duration.ofSeconds(10)).isAfter(expiration.toZonedDateTime()); } } diff --git a/api/src/main/java/io/minio/credentials/IamAwsProvider.java b/api/src/main/java/io/minio/credentials/IamAwsProvider.java index 08abb1050..08419ac8f 100644 --- a/api/src/main/java/io/minio/credentials/IamAwsProvider.java +++ b/api/src/main/java/io/minio/credentials/IamAwsProvider.java @@ -21,7 +21,7 @@ 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.Time; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -248,7 +248,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/errors/ErrorResponseException.java b/api/src/main/java/io/minio/errors/ErrorResponseException.java index d2755932d..f62d66976 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; @@ -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/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..27e3e9c13 100644 --- a/api/src/main/java/io/minio/messages/AccessControlList.java +++ b/api/src/main/java/io/minio/messages/AccessControlList.java @@ -20,10 +20,21 @@ 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}. */ +/** + * Helper class to denote 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 +53,182 @@ public AccessControlList( public List grants() { return Utils.unmodifiableList(grants); } + + @Override + public String toString() { + return String.format("AccessControlList{grants=%s}", Utils.stringify(grants)); + } + + @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)); + } + } + + @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)); + } + } + + @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 class. */ + 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()); + } + } + } + + @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..3af01a2c1 100644 --- a/api/src/main/java/io/minio/messages/AccessControlPolicy.java +++ b/api/src/main/java/io/minio/messages/AccessControlPolicy.java @@ -18,6 +18,7 @@ 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; @@ -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..3ae6b5667 --- /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; + +/** + * Common 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 89% rename from api/src/main/java/io/minio/messages/SelectObjectContentRequestBase.java rename to api/src/main/java/io/minio/messages/BaseSelectParameters.java index 3bce8fc8b..436f86a4a 100644 --- a/api/src/main/java/io/minio/messages/SelectObjectContentRequestBase.java +++ b/api/src/main/java/io/minio/messages/BaseSelectParameters.java @@ -20,9 +20,11 @@ import javax.annotation.Nonnull; import org.simpleframework.xml.Element; -/** Base class for {@link SelectObjectContentRequest} and {@link SelectParameters}. */ +/** + * Base class 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 +37,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..1b5b77bd6 100644 --- a/api/src/main/java/io/minio/messages/CORSConfiguration.java +++ b/api/src/main/java/io/minio/messages/CORSConfiguration.java @@ -46,6 +46,11 @@ public List rules() { return Utils.unmodifiableList(rules); } + @Override + public String toString() { + return String.format("CORSConfiguration{rules=%s}", Utils.stringify(rules)); + } + public static class CORSRule { @ElementList(entry = "AllowedHeader", inline = true, required = false) private List allowedHeaders; @@ -107,5 +112,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..835ea1e79 100644 --- a/api/src/main/java/io/minio/messages/Checksum.java +++ b/api/src/main/java/io/minio/messages/Checksum.java @@ -18,6 +18,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import io.minio.Utils; import java.util.Locale; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @@ -45,6 +46,21 @@ public class Checksum { public Checksum() {} + 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; } @@ -85,4 +101,21 @@ public Multimap headers() { addHeader(map, "SHA256", checksumSHA256); return map; } + + 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)); + } + + @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..66caf3ff7 100644 --- a/api/src/main/java/io/minio/messages/CompleteMultipartUpload.java +++ b/api/src/main/java/io/minio/messages/CompleteMultipartUpload.java @@ -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. */ 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..151f3463d 100644 --- a/api/src/main/java/io/minio/messages/CompleteMultipartUploadResult.java +++ b/api/src/main/java/io/minio/messages/CompleteMultipartUploadResult.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; @@ -27,7 +28,7 @@ */ @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..858f6f7eb 100644 --- a/api/src/main/java/io/minio/messages/Contents.java +++ b/api/src/main/java/io/minio/messages/Contents.java @@ -31,4 +31,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..4ad5a88e1 100644 --- a/api/src/main/java/io/minio/messages/CopyObjectResult.java +++ b/api/src/main/java/io/minio/messages/CopyObjectResult.java @@ -17,6 +17,8 @@ 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; @@ -28,30 +30,12 @@ */ @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..52635b48a 100644 --- a/api/src/main/java/io/minio/messages/CopyPartResult.java +++ b/api/src/main/java/io/minio/messages/CopyPartResult.java @@ -27,4 +27,9 @@ */ @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..842dfe8a4 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. */ 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/DeleteMarker.java b/api/src/main/java/io/minio/messages/DeleteMarker.java deleted file mode 100644 index 0e95b74ed..000000000 --- a/api/src/main/java/io/minio/messages/DeleteMarker.java +++ /dev/null @@ -1,31 +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; - -/** Helper class to denote delete marker information in {@link ListVersionsResult}. */ -@Root(name = "DeleteMarker", strict = false) -public class DeleteMarker extends Item { - public DeleteMarker() { - super(); - } - - public DeleteMarker(String prefix) { - super(prefix); - } -} 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..e6e48f3bc 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,6 +26,10 @@ 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 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; } + + @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 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/DeleteResult.java b/api/src/main/java/io/minio/messages/DeleteResult.java index c5c1a04e1..9bb051963 100644 --- a/api/src/main/java/io/minio/messages/DeleteResult.java +++ b/api/src/main/java/io/minio/messages/DeleteResult.java @@ -19,6 +19,7 @@ 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; @@ -32,26 +33,86 @@ @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)); + } + + @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)); + } + } + + @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..b7a3d8f8b 100644 --- a/api/src/main/java/io/minio/messages/ErrorResponse.java +++ b/api/src/main/java/io/minio/messages/ErrorResponse.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import java.io.Serializable; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; @@ -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/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..46e1b0e01 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,231 @@ 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}. + * Helper class to denote 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); + @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)); + } + } + + @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..a891fdc29 100644 --- a/api/src/main/java/io/minio/messages/GetObjectAttributesOutput.java +++ b/api/src/main/java/io/minio/messages/GetObjectAttributesOutput.java @@ -18,9 +18,7 @@ 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; @@ -97,50 +95,38 @@ 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)); + } + @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..ce17236be 100644 --- a/api/src/main/java/io/minio/messages/InitiateMultipartUploadResult.java +++ b/api/src/main/java/io/minio/messages/InitiateMultipartUploadResult.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; @@ -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..c5ee75bbf 100644 --- a/api/src/main/java/io/minio/messages/Initiator.java +++ b/api/src/main/java/io/minio/messages/Initiator.java @@ -16,13 +16,10 @@ 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}. - */ @Root(name = "Initiator", strict = false) public class Initiator { @Element(name = "ID", required = false) @@ -42,4 +39,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..2d638218b 100644 --- a/api/src/main/java/io/minio/messages/InputSerialization.java +++ b/api/src/main/java/io/minio/messages/InputSerialization.java @@ -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,103 @@ 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()); + } + + @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; + } + } + + @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; + } + } + + @Root(name = "Parquet") + public static class Parquet {} + + /** CSV/JSON object's compression format for select object content. */ + public enum CompressionType { + NONE, + GZIP, + BZIP2; + } + + /** Description the first line of input in CSV object. */ + public enum FileHeaderInfo { + USE, + IGNORE, + NONE; + } + + /** The type of 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..f4022feeb 100644 --- a/api/src/main/java/io/minio/messages/Item.java +++ b/api/src/main/java/io/minio/messages/Item.java @@ -16,13 +16,21 @@ 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 @@ -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,40 @@ 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)); + } + @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 +205,68 @@ 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)); + } + } + + @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 class. */ + 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..fb463cc27 100644 --- a/api/src/main/java/io/minio/messages/LegalHold.java +++ b/api/src/main/java/io/minio/messages/LegalHold.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; @@ -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..f7874f412 100644 --- a/api/src/main/java/io/minio/messages/LifecycleConfiguration.java +++ b/api/src/main/java/io/minio/messages/LifecycleConfiguration.java @@ -16,10 +16,14 @@ 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; @@ -35,18 +39,356 @@ @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)); + } + + @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)); + } + } + + @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); + } + } + + 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)); + } + } + + @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)); + } + } + + @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()); + } + } + + @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); + } + } + + @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..0ef1c3b15 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; @@ -61,4 +63,49 @@ 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)); + } + + @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..6a83cf206 100644 --- a/api/src/main/java/io/minio/messages/ListBucketResultV1.java +++ b/api/src/main/java/io/minio/messages/ListBucketResultV1.java @@ -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..c422bf742 100644 --- a/api/src/main/java/io/minio/messages/ListBucketResultV2.java +++ b/api/src/main/java/io/minio/messages/ListBucketResultV2.java @@ -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..b45b9fa9b 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; @@ -103,4 +105,122 @@ 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)); + } + + @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..a57074998 100644 --- a/api/src/main/java/io/minio/messages/ListObjectsResult.java +++ b/api/src/main/java/io/minio/messages/ListObjectsResult.java @@ -20,6 +20,7 @@ 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 @@ -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,40 @@ 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)); + } + + @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..c186d7f98 100644 --- a/api/src/main/java/io/minio/messages/ListPartsResult.java +++ b/api/src/main/java/io/minio/messages/ListPartsResult.java @@ -17,9 +17,7 @@ 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; @@ -29,7 +27,7 @@ */ @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() { @@ -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..6a1244411 100644 --- a/api/src/main/java/io/minio/messages/ListVersionsResult.java +++ b/api/src/main/java/io/minio/messages/ListVersionsResult.java @@ -74,4 +74,50 @@ 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)); + } + + @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()); + } + } + + @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..09ea5cb46 100644 --- a/api/src/main/java/io/minio/messages/LocationConstraint.java +++ b/api/src/main/java/io/minio/messages/LocationConstraint.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; import org.simpleframework.xml.Text; @@ -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..851a5bd6f 100644 --- a/api/src/main/java/io/minio/messages/NotificationConfiguration.java +++ b/api/src/main/java/io/minio/messages/NotificationConfiguration.java @@ -17,10 +17,14 @@ 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; /** @@ -34,63 +38,271 @@ @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)); } @Root(name = "EventBridgeConfiguration") - public static class EventBridgeConfiguration {} + public static class EventBridgeConfiguration { + @Override + public String toString() { + return String.format("EventBridgeConfiguration{}"); + } + } + + 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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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()); + } + } + + @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()); + } + } + + @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..82d3e1b64 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. + * href="http://docs.aws.amazon.com/AmazonS3/latest/dev/notification-content-structure.html">Notification + * Content Structure. */ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value = "UwF", @@ -36,4 +39,234 @@ public class NotificationRecords { public List events() { return Utils.unmodifiableList(events); } + + @Override + public String toString() { + return String.format("NotificationRecords{events=%s}", Utils.stringify(events)); + } + + @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)); + } + + @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)); + } + } + + @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)); + } + } + + 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)); + } + } + + @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)); + } + } + + /** 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..9459293f5 100644 --- a/api/src/main/java/io/minio/messages/ObjectLockConfiguration.java +++ b/api/src/main/java/io/minio/messages/ObjectLockConfiguration.java @@ -16,9 +16,13 @@ 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 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..4cbc0e8a4 100644 --- a/api/src/main/java/io/minio/messages/OutputSerialization.java +++ b/api/src/main/java/io/minio/messages/OutputSerialization.java @@ -26,25 +26,79 @@ @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)); + } + + @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; + } + } + + @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; + } + } + + /** Indicates whether to use quotation marks around output fields. */ + 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..2a73b2137 100644 --- a/api/src/main/java/io/minio/messages/Owner.java +++ b/api/src/main/java/io/minio/messages/Owner.java @@ -16,6 +16,7 @@ package io.minio.messages; +import io.minio.Utils; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @@ -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..9b50c350c 100644 --- a/api/src/main/java/io/minio/messages/Part.java +++ b/api/src/main/java/io/minio/messages/Part.java @@ -16,6 +16,8 @@ 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; @@ -25,7 +27,7 @@ * 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,35 @@ 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 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/Progress.java b/api/src/main/java/io/minio/messages/Progress.java index 71ba29590..32558a272 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. */ @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/QueueConfiguration.java b/api/src/main/java/io/minio/messages/QueueConfiguration.java deleted file mode 100644 index 2123b6505..000000000 --- a/api/src/main/java/io/minio/messages/QueueConfiguration.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 Queue configuration of {@link NotificationConfiguration}. */ -@Root(name = "QueueConfiguration", strict = false) -public class QueueConfiguration extends NotificationCommonConfiguration { - @Element(name = "Queue") - private String queue; - - public QueueConfiguration() { - super(); - } - - /** Returns queue. */ - public String queue() { - return queue; - } - - /** Sets queue. */ - public void setQueue(String queue) { - this.queue = queue; - } -} 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..e0e9485b2 100644 --- a/api/src/main/java/io/minio/messages/ReplicationConfiguration.java +++ b/api/src/main/java/io/minio/messages/ReplicationConfiguration.java @@ -25,6 +25,7 @@ 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 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,513 @@ 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)); + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + @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)); + } + } + + /** This is MinIO specific extension. */ + @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..429f08905 100644 --- a/api/src/main/java/io/minio/messages/RestoreRequest.java +++ b/api/src/main/java/io/minio/messages/RestoreRequest.java @@ -16,10 +16,20 @@ 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 { + @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()); + } + } + } + + @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"); + } + } + + @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); + } + } + + @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"); + } + } + + @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; + } + } + + @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 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()); + } + } + } + + @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; + } + } + + @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..1662f2b00 100644 --- a/api/src/main/java/io/minio/messages/Retention.java +++ b/api/src/main/java/io/minio/messages/Retention.java @@ -16,6 +16,8 @@ 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; @@ -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..8904f0d2d 100644 --- a/api/src/main/java/io/minio/messages/SelectObjectContentRequest.java +++ b/api/src/main/java/io/minio/messages/SelectObjectContentRequest.java @@ -30,14 +30,13 @@ @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,28 @@ public SelectObjectContentRequest( this.scanRange = new ScanRange(scanStartRange, scanEndRange); } } + + @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() {} + } + + @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/SseConfiguration.java b/api/src/main/java/io/minio/messages/SseConfiguration.java index 1107be67d..a6096106a 100644 --- a/api/src/main/java/io/minio/messages/SseConfiguration.java +++ b/api/src/main/java/io/minio/messages/SseConfiguration.java @@ -16,9 +16,13 @@ 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; /** @@ -28,27 +32,67 @@ * href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html">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)); + } + + @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..664a0abb4 100644 --- a/api/src/main/java/io/minio/messages/Stats.java +++ b/api/src/main/java/io/minio/messages/Stats.java @@ -24,30 +24,48 @@ @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/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..a38fe4f43 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/Version.java b/api/src/main/java/io/minio/messages/Version.java deleted file mode 100644 index 65eb57d97..000000000 --- a/api/src/main/java/io/minio/messages/Version.java +++ /dev/null @@ -1,31 +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; - -/** 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 Version(String prefix) { - super(prefix); - } -} diff --git a/api/src/main/java/io/minio/messages/VersioningConfiguration.java b/api/src/main/java/io/minio/messages/VersioningConfiguration.java index d67536586..272e2b2e8 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; @@ -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..eea90951a 100644 --- a/api/src/test/java/io/minio/MinioClientTest.java +++ b/api/src/test/java/io/minio/MinioClientTest.java @@ -19,7 +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; @@ -38,7 +37,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 +102,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -118,7 +117,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -129,7 +128,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -144,7 +143,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -156,7 +155,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -169,7 +168,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -185,7 +184,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -197,7 +196,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -213,7 +212,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -226,7 +225,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -243,7 +242,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -258,7 +257,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -273,7 +272,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -289,7 +288,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -306,7 +305,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -322,7 +321,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -338,7 +337,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -355,7 +354,7 @@ public void testAwsEndpoints() url = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("mybucket") .object("myobject") .build()); @@ -382,7 +381,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 +431,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 +469,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"); } @@ -484,7 +483,7 @@ public void testWriteSse1() client.putObject( PutObjectArgs.builder().bucket("mybucket").object("myobject").stream( new ByteArrayInputStream(new byte[] {}), 0, -1) - .sse(new ServerSideEncryptionCustomerKey(keyGen.generateKey())) + .sse(new ServerSideEncryption.CustomerKey(keyGen.generateKey())) .build()); Assert.fail("exception should be thrown"); } @@ -498,7 +497,7 @@ public void testWriteSse2() client.putObject( PutObjectArgs.builder().bucket("mybucket").object("myobject").stream( new ByteArrayInputStream(new byte[] {}), 0, -1) - .sse(new ServerSideEncryptionKms("keyId", myContext)) + .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..b481f0c41 100644 --- a/api/src/test/java/io/minio/StatObjectArgsTest.java +++ b/api/src/test/java/io/minio/StatObjectArgsTest.java @@ -24,25 +24,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 +54,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"); @@ -70,8 +70,8 @@ public void testEmptyObjectBuild2() { public void testBuild() throws NoSuchAlgorithmException, InvalidKeyException { 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/examples/ComposeObject.java b/examples/ComposeObject.java index 3cad7faa2..d3ca691f1 100644 --- a/examples/ComposeObject.java +++ b/examples/ComposeObject.java @@ -18,7 +18,6 @@ import io.minio.ComposeSource; import io.minio.MinioClient; import io.minio.ServerSideEncryption; -import io.minio.ServerSideEncryptionCustomerKey; import io.minio.errors.MinioException; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -71,13 +70,13 @@ public static void main(String[] args) } { - ServerSideEncryptionCustomerKey srcSsec = - new ServerSideEncryptionCustomerKey( + ServerSideEncryption.CustomerKey srcSsec = + new ServerSideEncryption.CustomerKey( new SecretKeySpec( "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8), "AES")); ServerSideEncryption sse = - new ServerSideEncryptionCustomerKey( + new ServerSideEncryption.CustomerKey( new SecretKeySpec( "12345678912345678912345678912345".getBytes(StandardCharsets.UTF_8), "AES")); diff --git a/examples/CopyObject.java b/examples/CopyObject.java index 6b6508f2a..cc205e80f 100644 --- a/examples/CopyObject.java +++ b/examples/CopyObject.java @@ -19,9 +19,6 @@ 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.errors.MinioException; import java.io.IOException; import java.security.InvalidKeyException; @@ -51,14 +48,14 @@ public static void main(String[] args) KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); Map myContext = new HashMap<>(); myContext.put("key1", "value1"); - ServerSideEncryption sseKms = new ServerSideEncryptionKms("Key-Id", myContext); + 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"); diff --git a/examples/DownloadObject.java b/examples/DownloadObject.java index f357842d0..0402ce356 100644 --- a/examples/DownloadObject.java +++ b/examples/DownloadObject.java @@ -16,7 +16,7 @@ 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; @@ -56,8 +56,8 @@ public static void main(String[] args) { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); // Download SSE-C encrypted 'my-objectname' from 'my-bucketname' to 'my-filename' minioClient.downloadObject( diff --git a/examples/GetPresignedObjectUrl.java b/examples/GetPresignedObjectUrl.java index e154b88cb..bf8342e86 100644 --- a/examples/GetPresignedObjectUrl.java +++ b/examples/GetPresignedObjectUrl.java @@ -15,9 +15,9 @@ */ 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; @@ -46,7 +46,7 @@ public static void main(String[] args) String url = minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.DELETE) + .method(Http.Method.DELETE) .bucket("my-bucketname") .object("my-objectname") .expiry(60 * 60 * 24) diff --git a/examples/ListBuckets.java b/examples/ListBuckets.java index f0e15263d..aa297d755 100644 --- a/examples/ListBuckets.java +++ b/examples/ListBuckets.java @@ -18,7 +18,7 @@ import io.minio.MinioClient; import io.minio.Result; import io.minio.errors.MinioException; -import io.minio.messages.Bucket; +import io.minio.messages.ListAllMyBucketsResult; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -43,9 +43,10 @@ public static void main(String[] args) // .build(); // List buckets we have atleast read access. - Iterable> results = minioClient.listBuckets(ListBucketsArgs.builder().build()); - for (Result result : results) { - Bucket bucket = result.get(); + 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", diff --git a/examples/ListenBucketNotification.java b/examples/ListenBucketNotification.java index d0b5bc80b..3ef5ecc01 100644 --- a/examples/ListenBucketNotification.java +++ b/examples/ListenBucketNotification.java @@ -19,7 +19,6 @@ 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; @@ -55,8 +54,9 @@ public static void main(String[] args) .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"); + NotificationRecords.Event event = records.events().get(0); + System.out.println( + event.bucket().name() + "/" + event.object().key() + " has been created"); } } catch (IOException e) { System.out.println("Error occurred: " + e); diff --git a/examples/PresignedGetObject.java b/examples/PresignedGetObject.java index cf9c889d2..6e2edc5b0 100644 --- a/examples/PresignedGetObject.java +++ b/examples/PresignedGetObject.java @@ -15,9 +15,9 @@ */ 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; @@ -46,7 +46,7 @@ public static void main(String[] args) String url = minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket("my-bucketname") .object("my-objectname") .expiry(60 * 60 * 24) diff --git a/examples/PresignedPutObject.java b/examples/PresignedPutObject.java index e231de21e..d1f03af3b 100644 --- a/examples/PresignedPutObject.java +++ b/examples/PresignedPutObject.java @@ -15,9 +15,9 @@ */ 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; @@ -52,7 +52,7 @@ public static void main(String[] args) String url = minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) + .method(Http.Method.PUT) .bucket("my-bucketname") .object("my-objectname") .expiry(60 * 60 * 24) diff --git a/examples/PutObject.java b/examples/PutObject.java index 06fdd75ef..4c29bc886 100644 --- a/examples/PutObject.java +++ b/examples/PutObject.java @@ -17,9 +17,6 @@ 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; @@ -95,8 +92,8 @@ public static void main(String[] args) // 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()); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); // Create encrypted object 'my-objectname' using SSE-C in 'my-bucketname' with content from // the input stream. @@ -115,7 +112,7 @@ public static void main(String[] args) Map myContext = new HashMap<>(); myContext.put("key1", "value1"); - ServerSideEncryption sseKms = new ServerSideEncryptionKms("Key-Id", myContext); + ServerSideEncryption sseKms = new ServerSideEncryption.KMS("Key-Id", myContext); // Create encrypted object 'my-objectname' using SSE-KMS in 'my-bucketname' with content // from the input stream. @@ -132,7 +129,7 @@ public static void main(String[] args) // Create a InputStream for object upload. ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - ServerSideEncryption sseS3 = new ServerSideEncryptionS3(); + ServerSideEncryption sseS3 = new ServerSideEncryption.S3(); // Create encrypted object 'my-objectname' using SSE-S3 in 'my-bucketname' with content // from the input stream. diff --git a/examples/RemoveObjects.java b/examples/RemoveObjects.java index 11827c3a7..48d6e7b13 100644 --- a/examples/RemoveObjects.java +++ b/examples/RemoveObjects.java @@ -18,8 +18,8 @@ import io.minio.RemoveObjectsArgs; import io.minio.Result; import io.minio.errors.MinioException; -import io.minio.messages.DeleteError; -import io.minio.messages.DeleteObject; +import io.minio.messages.DeleteRequest; +import io.minio.messages.DeleteResult; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -45,15 +45,15 @@ public static void main(String[] args) // .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 = + List objects = new LinkedList<>(); + objects.add(new DeleteRequest.Object("my-objectname1")); + objects.add(new DeleteRequest.Object("my-objectname2")); + objects.add(new DeleteRequest.Object("my-objectname3")); + 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()); } diff --git a/examples/SelectObjectContent.java b/examples/SelectObjectContent.java index 247a08a1a..987237763 100644 --- a/examples/SelectObjectContent.java +++ b/examples/SelectObjectContent.java @@ -19,10 +19,8 @@ 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; @@ -65,9 +63,11 @@ public static void main(String[] args) String sqlExpression = "select * from S3Object"; InputSerialization is = - new InputSerialization(null, false, null, null, FileHeaderInfo.USE, null, null, null); + InputSerialization.newCSV( + null, false, null, null, InputSerialization.FileHeaderInfo.USE, null, null, null); OutputSerialization os = - new OutputSerialization(null, null, null, QuoteFields.ASNEEDED, null); + OutputSerialization.newCSV( + null, null, null, OutputSerialization.QuoteFields.ASNEEDED, null); SelectResponseStream stream = minioClient.selectObjectContent( diff --git a/examples/SetBucketLifecycle.java b/examples/SetBucketLifecycle.java index 2b512a5c1..630f830cc 100644 --- a/examples/SetBucketLifecycle.java +++ b/examples/SetBucketLifecycle.java @@ -17,10 +17,8 @@ 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; @@ -48,13 +46,13 @@ public static void main(String[] args) // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") // .build(); - List rules = new LinkedList<>(); + List rules = new LinkedList<>(); rules.add( - new LifecycleRule( + new LifecycleConfiguration.Rule( Status.ENABLED, null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), "rule2", null, null, diff --git a/examples/SetBucketNotification.java b/examples/SetBucketNotification.java index a3f1cf496..90d137037 100644 --- a/examples/SetBucketNotification.java +++ b/examples/SetBucketNotification.java @@ -19,12 +19,10 @@ 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. */ @@ -45,22 +43,24 @@ public static void main(String[] args) // .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY") // .build(); - NotificationConfiguration config = new NotificationConfiguration(); - - // 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); + 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); // Set updated notification configuration. minioClient.setBucketNotification( diff --git a/examples/SetBucketReplication.java b/examples/SetBucketReplication.java index 5f35de2ce..4dceec983 100644 --- a/examples/SetBucketReplication.java +++ b/examples/SetBucketReplication.java @@ -17,12 +17,8 @@ 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; @@ -55,20 +51,20 @@ public static void main(String[] args) tags.put("key1", "value1"); tags.put("key2", "value2"); - ReplicationRule rule = - new ReplicationRule( - new DeleteMarkerReplication(Status.DISABLED), - new ReplicationDestination( + 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 RuleFilter(new AndOperator("TaxDocs", tags)), + new Filter(new Filter.And("TaxDocs", tags)), "rule1", null, 1, null, Status.ENABLED); - List rules = new LinkedList<>(); + List rules = new LinkedList<>(); rules.add(rule); ReplicationConfiguration config = diff --git a/examples/SetObjectLockConfiguration.java b/examples/SetObjectLockConfiguration.java index 716518c9f..d057554a5 100644 --- a/examples/SetObjectLockConfiguration.java +++ b/examples/SetObjectLockConfiguration.java @@ -18,7 +18,6 @@ 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; @@ -45,7 +44,8 @@ public static void main(String[] args) // Declaring config with Retention mode as Compliance and duration as 100 days ObjectLockConfiguration config = - new ObjectLockConfiguration(RetentionMode.COMPLIANCE, new RetentionDurationDays(100)); + new ObjectLockConfiguration( + RetentionMode.COMPLIANCE, new ObjectLockConfiguration.RetentionDurationDays(100)); minioClient.setObjectLockConfiguration( SetObjectLockConfigurationArgs.builder() diff --git a/examples/StatObject.java b/examples/StatObject.java index f6a3e13d1..99bac0721 100644 --- a/examples/StatObject.java +++ b/examples/StatObject.java @@ -15,7 +15,7 @@ */ 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; @@ -46,8 +46,8 @@ public static void main(String[] args) KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); String versionId = "ac38316c-fe14-4f96-9f76-8f675ae5a79e"; { diff --git a/examples/UploadObject.java b/examples/UploadObject.java index 35abedc48..26ca3601a 100644 --- a/examples/UploadObject.java +++ b/examples/UploadObject.java @@ -15,7 +15,7 @@ */ 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; @@ -56,8 +56,8 @@ public static void main(String[] args) { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - ServerSideEncryptionCustomerKey ssec = - new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + ServerSideEncryption.CustomerKey ssec = + new ServerSideEncryption.CustomerKey(keyGen.generateKey()); // Upload 'my-filename' as object encrypted 'my-objectname' in 'my-bucketname'. minioClient.uploadObject( diff --git a/functional/FunctionalTest.java b/functional/FunctionalTest.java index 3f2234333..16153ce30 100644 --- a/functional/FunctionalTest.java +++ b/functional/FunctionalTest.java @@ -55,6 +55,7 @@ import io.minio.GetObjectRetentionArgs; import io.minio.GetObjectTagsArgs; import io.minio.GetPresignedObjectUrlArgs; +import io.minio.Http; import io.minio.IsObjectLegalHoldEnabledArgs; import io.minio.ListBucketsArgs; import io.minio.ListObjectsArgs; @@ -73,9 +74,6 @@ 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; @@ -96,38 +94,22 @@ 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.AccessControlList; 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.DeleteRequest; import io.minio.messages.EventType; -import io.minio.messages.Expiration; -import io.minio.messages.FileHeaderInfo; -import io.minio.messages.GranteeType; +import io.minio.messages.Filter; import io.minio.messages.InputSerialization; import io.minio.messages.LifecycleConfiguration; -import io.minio.messages.LifecycleRule; +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.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; @@ -205,8 +187,8 @@ public class FunctionalTest { private static MinioClient client = null; private static TestMinioAdminClient adminClientTests; - private static ServerSideEncryptionCustomerKey ssec = null; - private static ServerSideEncryption sseS3 = new ServerSideEncryptionS3(); + private static ServerSideEncryption.CustomerKey ssec = null; + private static ServerSideEncryption sseS3 = new ServerSideEncryption.S3(); private static ServerSideEncryption sseKms = null; static { @@ -220,7 +202,7 @@ public class FunctionalTest { try { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - ssec = new ServerSideEncryptionCustomerKey(keyGen.generateKey()); + ssec = new ServerSideEncryption.CustomerKey(keyGen.generateKey()); } catch (InvalidKeyException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } @@ -228,11 +210,7 @@ public class FunctionalTest { public static OkHttpClient newHttpClient() { try { - return HttpUtils.disableCertCheck( - HttpUtils.newDefaultHttpClient( - TimeUnit.MINUTES.toMillis(5), - TimeUnit.MINUTES.toMillis(5), - TimeUnit.MINUTES.toMillis(5))); + return Http.disableCertCheck(Http.newDefaultClient()); } catch (KeyManagementException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } @@ -574,9 +552,9 @@ public static void listBuckets() throws Exception { expectedBucketNames.add(bucketName); List bucketNames = new LinkedList<>(); - for (Result result : + for (Result result : client.listBuckets(ListBucketsArgs.builder().maxBuckets(1).build())) { - Bucket bucket = result.get(); + ListAllMyBucketsResult.Bucket bucket = result.get(); if (expectedBucketNames.contains(bucket.name())) { bucketNames.add(bucket.name()); } @@ -1012,9 +990,9 @@ public static void testStatObject( try { client.putObject(args); try { - ServerSideEncryptionCustomerKey ssec = null; - if (args.sse() instanceof ServerSideEncryptionCustomerKey) { - ssec = (ServerSideEncryptionCustomerKey) args.sse(); + ServerSideEncryption.CustomerKey ssec = null; + if (args.sse() instanceof ServerSideEncryption.CustomerKey) { + ssec = (ServerSideEncryption.CustomerKey) args.sse(); } StatObjectResponse stat = client.statObject( @@ -1381,11 +1359,11 @@ public static List createObjects(String bucketName, int cou public static void removeObjects(String bucketName, List results) throws Exception { - List objects = + List objects = results.stream() .map( result -> { - return new DeleteObject(result.object(), result.versionId()); + return new DeleteRequest.Object(result.object(), result.versionId()); }) .collect(Collectors.toList()); for (Result r : @@ -1625,7 +1603,7 @@ public static void testGetPresignedObjectUrlForGet() throws Exception { testTags = "[GET]"; testGetPresignedUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket(bucketName) .object(objectName) .build(), @@ -1634,7 +1612,7 @@ public static void testGetPresignedObjectUrlForGet() throws Exception { testTags = "[GET, expiry]"; testGetPresignedUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket(bucketName) .object(objectName) .expiry(1, TimeUnit.DAYS) @@ -1646,7 +1624,7 @@ public static void testGetPresignedObjectUrlForGet() throws Exception { queryParams.put("response-content-type", "application/json"); testGetPresignedUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket(bucketName) .object(objectName) .expiry(1, TimeUnit.DAYS) @@ -1702,7 +1680,7 @@ public static void testGetPresignedObjectUrlForPut() throws Exception { data, expectedChecksum, GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) + .method(Http.Method.PUT) .bucket(bucketName) .object(objectName) .build()); @@ -1712,7 +1690,7 @@ public static void testGetPresignedObjectUrlForPut() throws Exception { data, expectedChecksum, GetPresignedObjectUrlArgs.builder() - .method(Method.PUT) + .method(Http.Method.PUT) .bucket(bucketName) .object(objectName) .expiry(1, TimeUnit.DAYS) @@ -1760,7 +1738,7 @@ public static void getPresignedPostFormData() throws Exception { String urlString = client.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() - .method(Method.GET) + .method(Http.Method.GET) .bucket(bucketName) .object("x") .build()); @@ -1815,9 +1793,9 @@ public static void testCopyObject( } else { client.copyObject(args); - ServerSideEncryptionCustomerKey ssec = null; - if (sse instanceof ServerSideEncryptionCustomerKey) { - ssec = (ServerSideEncryptionCustomerKey) sse; + ServerSideEncryption.CustomerKey ssec = null; + if (sse instanceof ServerSideEncryption.CustomerKey) { + ssec = (ServerSideEncryption.CustomerKey) sse; } client.statObject( StatObjectArgs.builder() @@ -2464,7 +2442,8 @@ public static void setObjectLockConfiguration() throws Exception { client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); try { ObjectLockConfiguration config = - new ObjectLockConfiguration(RetentionMode.COMPLIANCE, new RetentionDurationDays(10)); + new ObjectLockConfiguration( + RetentionMode.COMPLIANCE, new ObjectLockConfiguration.RetentionDurationDays(10)); client.setObjectLockConfiguration( SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build()); } finally { @@ -2477,7 +2456,8 @@ public static void setObjectLockConfiguration() throws Exception { } public static void testGetObjectLockConfiguration( - String bucketName, RetentionMode mode, RetentionDuration duration) throws Exception { + String bucketName, RetentionMode mode, ObjectLockConfiguration.RetentionDuration duration) + throws Exception { ObjectLockConfiguration expectedConfig = new ObjectLockConfiguration(mode, duration); client.setObjectLockConfiguration( SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(expectedConfig).build()); @@ -2506,9 +2486,13 @@ public static void getObjectLockConfiguration() throws Exception { client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(true).build()); try { testGetObjectLockConfiguration( - bucketName, RetentionMode.COMPLIANCE, new RetentionDurationDays(10)); + bucketName, + RetentionMode.COMPLIANCE, + new ObjectLockConfiguration.RetentionDurationDays(10)); testGetObjectLockConfiguration( - bucketName, RetentionMode.GOVERNANCE, new RetentionDurationYears(1)); + bucketName, + RetentionMode.GOVERNANCE, + new ObjectLockConfiguration.RetentionDurationYears(1)); } finally { client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); } @@ -2533,7 +2517,8 @@ public static void deleteObjectLockConfiguration() throws Exception { client.deleteObjectLockConfiguration( DeleteObjectLockConfigurationArgs.builder().bucket(bucketName).build()); ObjectLockConfiguration config = - new ObjectLockConfiguration(RetentionMode.COMPLIANCE, new RetentionDurationDays(10)); + new ObjectLockConfiguration( + RetentionMode.COMPLIANCE, new ObjectLockConfiguration.RetentionDurationDays(10)); client.setObjectLockConfiguration( SetObjectLockConfigurationArgs.builder().bucket(bucketName).config(config).build()); client.deleteObjectLockConfiguration( @@ -2787,7 +2772,7 @@ public static void deleteBucketPolicy() throws Exception { } } - public static void testSetBucketLifecycle(String bucketName, LifecycleRule... rules) + public static void testSetBucketLifecycle(String bucketName, LifecycleConfiguration.Rule... rules) throws Exception { LifecycleConfiguration config = new LifecycleConfiguration(Arrays.asList(rules)); client.setBucketLifecycle( @@ -2807,11 +2792,11 @@ public static void setBucketLifecycle() throws Exception { try { testSetBucketLifecycle( bucketName, - new LifecycleRule( + new LifecycleConfiguration.Rule( Status.ENABLED, null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), "rule2", null, null, @@ -2840,11 +2825,11 @@ public static void deleteBucketLifecycle() throws Exception { DeleteBucketLifecycleArgs.builder().bucket(bucketName).build()); testSetBucketLifecycle( bucketName, - new LifecycleRule( + new LifecycleConfiguration.Rule( Status.ENABLED, null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), "rule2", null, null, @@ -2876,11 +2861,11 @@ public static void getBucketLifecycle() throws Exception { Assert.assertNull("config: expected: , got: ", config); testSetBucketLifecycle( bucketName, - new LifecycleRule( + new LifecycleConfiguration.Rule( Status.ENABLED, null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter("logs/"), + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter("logs/"), "rule2", null, null, @@ -2888,12 +2873,12 @@ public static void getBucketLifecycle() throws Exception { config = client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucketName).build()); Assert.assertNotNull("config: expected: , got: ", config); - List rules = config.rules(); + List rules = config.rules(); Assert.assertEquals( "config.rules().size(): expected: 1, got: " + config.rules().size(), 1, config.rules().size()); - LifecycleRule rule = rules.get(0); + LifecycleConfiguration.Rule rule = rules.get(0); Assert.assertEquals( "rule.status(): expected: " + Status.ENABLED + ", got: " + rule.status(), rule.status(), @@ -2913,11 +2898,11 @@ public static void getBucketLifecycle() throws Exception { testSetBucketLifecycle( bucketName, - new LifecycleRule( + new LifecycleConfiguration.Rule( Status.ENABLED, null, - new Expiration((ZonedDateTime) null, 365, null), - new RuleFilter(""), + new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null), + new Filter(""), null, null, null, @@ -2961,21 +2946,23 @@ public static void setBucketNotification() throws Exception { 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); - + 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 { @@ -3003,18 +2990,19 @@ public static void getBucketNotification() throws Exception { 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); - + 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()); @@ -3022,11 +3010,12 @@ public static void getBucketNotification() throws Exception { 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) { + 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)); } @@ -3055,21 +3044,23 @@ public static void deleteBucketNotification() throws Exception { 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); - + 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()); @@ -3079,7 +3070,7 @@ public static void deleteBucketNotification() throws Exception { config = client.getBucketNotification( GetBucketNotificationArgs.builder().bucket(bucketName).build()); - if (config.queueConfigurationList().size() != 0) { + if (config.queueConfigurations().size() != 0) { System.out.println("config: expected: , got: " + Xml.marshal(config)); } } finally { @@ -3128,8 +3119,8 @@ public static void listenBucketNotification() throws Exception { } boolean found = false; - for (Event event : records.events()) { - if (event.objectName().equals("prefix-random-suffix")) { + for (NotificationRecords.Event event : records.events()) { + if ("prefix-random-suffix".equals(event.object().key())) { found = true; break; } @@ -3183,9 +3174,11 @@ public static void selectObjectContent() throws Exception { .build()); InputSerialization is = - new InputSerialization(null, false, null, null, FileHeaderInfo.USE, null, null, null); + InputSerialization.newCSV( + null, false, null, null, InputSerialization.FileHeaderInfo.USE, null, null, null); OutputSerialization os = - new OutputSerialization(null, null, null, QuoteFields.ASNEEDED, null); + OutputSerialization.newCSV( + null, null, null, OutputSerialization.QuoteFields.ASNEEDED, null); responseStream = client.selectObjectContent( @@ -3206,18 +3199,15 @@ public static void selectObjectContent() throws Exception { Stats stats = responseStream.stats(); Assert.assertNotNull("stats is null", stats); - Assert.assertEquals( + Assert.assertTrue( "stats.bytesScanned mismatch; expected: 258, got: " + stats.bytesScanned(), - stats.bytesScanned(), - 256); - Assert.assertEquals( + stats.bytesScanned() == 256); + Assert.assertTrue( "stats.bytesProcessed mismatch; expected: 258, got: " + stats.bytesProcessed(), - stats.bytesProcessed(), - 256); - Assert.assertEquals( + stats.bytesProcessed() == 256); + Assert.assertTrue( "stats.bytesReturned mismatch; expected: 222, got: " + stats.bytesReturned(), - stats.bytesReturned(), - 222); + stats.bytesReturned() == 222); mintSuccessLog(methodName, testArgs, startTime); } catch (Exception e) { handleException(methodName, testArgs, startTime, e); @@ -3600,18 +3590,18 @@ public static void getObjectAcl() throws Exception { GetObjectAclArgs.builder().bucket(bucketName).object(objectName).build()); Assert.assertEquals( "granteeType: expected: " - + GranteeType.CANONICAL_USER + + AccessControlList.Type.CANONICAL_USER + ", got: " + policy.accessControlList().grants().get(0).grantee().type(), policy.accessControlList().grants().get(0).grantee().type(), - GranteeType.CANONICAL_USER); + AccessControlList.Type.CANONICAL_USER); Assert.assertEquals( "permission: expected: " - + Permission.FULL_CONTROL + + AccessControlList.Permission.FULL_CONTROL + ", got: " + policy.accessControlList().grants().get(0).permission(), policy.accessControlList().grants().get(0).permission(), - Permission.FULL_CONTROL); + AccessControlList.Permission.FULL_CONTROL); mintSuccessLog(methodName, null, startTime); } finally { client.removeObject( @@ -3686,19 +3676,20 @@ public static void setBucketReplication() throws Exception { 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), + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, replicationBucketArn, null, null, null, null), null, - new RuleFilter(new AndOperator("TaxDocs", tags)), + new Filter(new Filter.And("TaxDocs", tags)), "rule1", null, 1, null, Status.ENABLED); - List rules = new LinkedList<>(); + List rules = new LinkedList<>(); rules.add(rule); ReplicationConfiguration config = new ReplicationConfiguration(replicationRole, rules); @@ -3735,19 +3726,20 @@ public static void getBucketReplication() throws Exception { 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), + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, replicationBucketArn, null, null, null, null), null, - new RuleFilter(new AndOperator("TaxDocs", tags)), + new Filter(new Filter.And("TaxDocs", tags)), "rule1", null, 1, null, Status.ENABLED); - List rules = new LinkedList<>(); + List rules = new LinkedList<>(); rules.add(rule); config = new ReplicationConfiguration(replicationRole, rules); @@ -3785,19 +3777,20 @@ public static void deleteBucketReplication() throws Exception { 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), + ReplicationConfiguration.Rule rule = + new ReplicationConfiguration.Rule( + new ReplicationConfiguration.DeleteMarkerReplication(Status.DISABLED), + new ReplicationConfiguration.Destination( + null, null, replicationBucketArn, null, null, null, null), null, - new RuleFilter(new AndOperator("TaxDocs", tags)), + new Filter(new Filter.And("TaxDocs", tags)), "rule1", null, 1, null, Status.ENABLED); - List rules = new LinkedList<>(); + List rules = new LinkedList<>(); rules.add(rule); ReplicationConfiguration config = new ReplicationConfiguration(replicationRole, rules); @@ -4224,7 +4217,7 @@ public static void main(String[] args) throws Exception { if (kmsKeyName != null) { Map myContext = new HashMap<>(); myContext.put("key1", "value1"); - sseKms = new ServerSideEncryptionKms(kmsKeyName, myContext); + sseKms = new ServerSideEncryption.KMS(kmsKeyName, myContext); } int exitValue = 0;