From 030788ec234ba98f61bfeb620e8547279e4fc4fe Mon Sep 17 00:00:00 2001 From: "Bala.FA" Date: Fri, 5 Jun 2020 17:29:53 +0530 Subject: [PATCH] add arg builder support to copyObject API --- api/src/main/java/io/minio/BaseArgs.java | 10 +- api/src/main/java/io/minio/BucketArgs.java | 15 +- .../main/java/io/minio/CopyObjectArgs.java | 148 ++++ .../java/io/minio/DeleteObjectTagsArgs.java | 5 +- api/src/main/java/io/minio/Directive.java | 23 + .../io/minio/DisableObjectLegalHoldArgs.java | 4 +- .../java/io/minio/DownloadObjectArgs.java | 12 +- .../io/minio/EnableObjectLegalHoldArgs.java | 4 +- api/src/main/java/io/minio/GetObjectArgs.java | 4 +- .../java/io/minio/GetObjectRetentionArgs.java | 5 +- .../main/java/io/minio/GetObjectTagsArgs.java | 4 +- .../io/minio/GetPresignedObjectUrlArgs.java | 5 +- .../minio/IsObjectLegalHoldEnabledArgs.java | 4 +- .../minio/ListenBucketNotificationArgs.java | 4 +- api/src/main/java/io/minio/MinioClient.java | 355 +++++++- api/src/main/java/io/minio/ObjectArgs.java | 30 +- ...secObjectArgs.java => ObjectReadArgs.java} | 17 +- .../main/java/io/minio/ObjectVersionArgs.java | 36 + .../main/java/io/minio/ObjectWriteArgs.java | 169 ++++ api/src/main/java/io/minio/PutObjectArgs.java | 164 ++++ .../io/minio/RemoveIncompleteUploadArgs.java | 4 +- .../main/java/io/minio/RemoveObjectArgs.java | 4 +- .../io/minio/SelectObjectContentArgs.java | 4 +- .../io/minio/SetBucketEncryptionArgs.java | 4 +- .../java/io/minio/SetBucketLifeCycleArgs.java | 4 +- .../io/minio/SetBucketNotificationArgs.java | 4 +- .../java/io/minio/SetBucketPolicyArgs.java | 4 +- .../main/java/io/minio/SetBucketTagsArgs.java | 9 +- .../io/minio/SetDefaultRetentionArgs.java | 4 +- .../java/io/minio/SetObjectRetentionArgs.java | 9 +- .../main/java/io/minio/SetObjectTagsArgs.java | 13 +- .../main/java/io/minio/StatObjectArgs.java | 4 +- .../test/java/io/minio/MinioClientTest.java | 20 +- docs/API.md | 79 +- examples/CopyObject.java | 174 +++- examples/CopyObjectEncrypted.java | 92 -- examples/CopyObjectEncryptedKms.java | 85 -- examples/CopyObjectEncryptedS3.java | 80 -- examples/CopyObjectMetadata.java | 102 --- examples/PutGetObjectEncrypted.java | 99 --- examples/PutObject.java | 111 ++- examples/PutObjectEncryptedKms.java | 75 -- examples/PutObjectEncryptedS3.java | 71 -- examples/PutObjectProgressBar.java | 7 +- examples/PutObjectUiProgressBar.java | 6 +- examples/PutObjectWithMetadata.java | 95 --- examples/SelectObjectContent.java | 6 +- functional/FunctionalTest.java | 803 ++++++------------ 48 files changed, 1504 insertions(+), 1486 deletions(-) create mode 100644 api/src/main/java/io/minio/CopyObjectArgs.java create mode 100644 api/src/main/java/io/minio/Directive.java rename api/src/main/java/io/minio/{SsecObjectArgs.java => ObjectReadArgs.java} (72%) create mode 100644 api/src/main/java/io/minio/ObjectVersionArgs.java create mode 100644 api/src/main/java/io/minio/ObjectWriteArgs.java create mode 100644 api/src/main/java/io/minio/PutObjectArgs.java delete mode 100644 examples/CopyObjectEncrypted.java delete mode 100644 examples/CopyObjectEncryptedKms.java delete mode 100644 examples/CopyObjectEncryptedS3.java delete mode 100644 examples/CopyObjectMetadata.java delete mode 100644 examples/PutGetObjectEncrypted.java delete mode 100644 examples/PutObjectEncryptedKms.java delete mode 100644 examples/PutObjectEncryptedS3.java delete mode 100644 examples/PutObjectWithMetadata.java diff --git a/api/src/main/java/io/minio/BaseArgs.java b/api/src/main/java/io/minio/BaseArgs.java index 1964149a2..543112e32 100644 --- a/api/src/main/java/io/minio/BaseArgs.java +++ b/api/src/main/java/io/minio/BaseArgs.java @@ -59,11 +59,17 @@ protected void validateNotEmptyString(String arg, String argName) { } } + protected void validateNullOrNotEmptyString(String arg, String argName) { + if (arg != null && arg.isEmpty()) { + throw new IllegalArgumentException(argName + " must be a non-empty string."); + } + } + public Builder() { this.operations = new ArrayList<>(); } - private Multimap copyMultimap(Multimap multimap) { + protected Multimap copyMultimap(Multimap multimap) { Multimap multimapCopy = HashMultimap.create(); if (multimap != null) { multimapCopy.putAll(multimap); @@ -71,7 +77,7 @@ private Multimap copyMultimap(Multimap multimap) return Multimaps.unmodifiableMultimap(multimapCopy); } - private Multimap toMultimap(Map map) { + protected Multimap toMultimap(Map map) { Multimap multimap = HashMultimap.create(); if (map != null) { multimap.putAll(Multimaps.forMap(map)); diff --git a/api/src/main/java/io/minio/BucketArgs.java b/api/src/main/java/io/minio/BucketArgs.java index 2c2520a38..b6fc44131 100644 --- a/api/src/main/java/io/minio/BucketArgs.java +++ b/api/src/main/java/io/minio/BucketArgs.java @@ -32,10 +32,8 @@ public String region() { /** Base argument builder class for {@link BucketArgs}. */ public abstract static class Builder, A extends BucketArgs> extends BaseArgs.Builder { - private void validateName(String name) { - if (name == null) { - throw new IllegalArgumentException("null bucket name"); - } + protected void validateBucketName(String name) { + validateNotNull(name, "bucket name"); // Bucket names cannot be no less than 3 and no more than 63 characters long. if (name.length() < 3 || name.length() > 63) { @@ -59,20 +57,17 @@ private void validateName(String name) { } private void validateRegion(String region) { - if (region != null && region.isEmpty()) { - throw new IllegalArgumentException("region cannot be empty"); - } + validateNullOrNotEmptyString(region, "region"); } @Override protected void validate(A args) { - validateName(args.bucketName); - validateRegion(args.region); + validateBucketName(args.bucketName); } @SuppressWarnings("unchecked") // Its safe to type cast to B as B extends this class. public B bucket(String name) { - validateName(name); + validateBucketName(name); operations.add(args -> args.bucketName = name); return (B) this; } diff --git a/api/src/main/java/io/minio/CopyObjectArgs.java b/api/src/main/java/io/minio/CopyObjectArgs.java new file mode 100644 index 000000000..cbfe74292 --- /dev/null +++ b/api/src/main/java/io/minio/CopyObjectArgs.java @@ -0,0 +1,148 @@ +/* + * 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.time.ZonedDateTime; +import okhttp3.HttpUrl; + +/** Argument class of MinioClient.copyObject(). */ +public class CopyObjectArgs extends ObjectWriteArgs { + private String srcBucket; + private String srcObject; + private String srcVersionId; + private ServerSideEncryptionCustomerKey srcSsec; + private String srcMatchETag; + private String srcNotMatchETag; + private ZonedDateTime srcModifiedSince; + private ZonedDateTime srcUnmodifiedSince; + private Directive metadataDirective; + private Directive taggingDirective; + + public String srcBucket() { + return srcBucket; + } + + public String srcObject() { + return srcObject; + } + + public String srcVersionId() { + return srcVersionId; + } + + public ServerSideEncryptionCustomerKey srcSsec() { + return srcSsec; + } + + public String srcMatchETag() { + return srcMatchETag; + } + + public String srcNotMatchETag() { + return srcNotMatchETag; + } + + public ZonedDateTime srcModifiedSince() { + return srcModifiedSince; + } + + public ZonedDateTime srcUnmodifiedSince() { + return srcUnmodifiedSince; + } + + public Directive metadataDirective() { + return metadataDirective; + } + + public Directive taggingDirective() { + return taggingDirective; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public void validateSse(HttpUrl url) { + super.validateSse(url); + checkSse(srcSsec, url); + } + + /** Argument builder of {@link CopyObjectArgs}. */ + public static final class Builder extends ObjectWriteArgs.Builder { + @Override + protected void validate(CopyObjectArgs args) { + super.validate(args); + validateBucketName(args.srcBucket); + } + + public Builder srcBucket(String srcBucket) { + validateBucketName(srcBucket); + operations.add(args -> args.srcBucket = srcBucket); + return this; + } + + public Builder srcObject(String srcObject) { + validateNullOrNotEmptyString(srcObject, "source object"); + operations.add(args -> args.srcObject = srcObject); + return this; + } + + public Builder srcVersionId(String srcVersionId) { + validateNullOrNotEmptyString(srcVersionId, "source version ID"); + operations.add(args -> args.srcVersionId = srcVersionId); + return this; + } + + public Builder srcSsec(ServerSideEncryptionCustomerKey srcSsec) { + operations.add(args -> args.srcSsec = srcSsec); + return this; + } + + public Builder srcMatchETag(String etag) { + validateNullOrNotEmptyString(etag, "etag"); + operations.add(args -> args.srcMatchETag = etag); + return this; + } + + public Builder srcNotMatchETag(String etag) { + validateNullOrNotEmptyString(etag, "etag"); + operations.add(args -> args.srcNotMatchETag = etag); + return this; + } + + public Builder srcModifiedSince(ZonedDateTime modifiedTime) { + operations.add(args -> args.srcModifiedSince = modifiedTime); + return this; + } + + public Builder srcUnmodifiedSince(ZonedDateTime modifiedTime) { + operations.add(args -> args.srcUnmodifiedSince = modifiedTime); + return this; + } + + public Builder metadataDirective(Directive directive) { + operations.add(args -> args.metadataDirective = directive); + return this; + } + + public Builder taggingDirective(Directive directive) { + operations.add(args -> args.taggingDirective = directive); + return this; + } + } +} diff --git a/api/src/main/java/io/minio/DeleteObjectTagsArgs.java b/api/src/main/java/io/minio/DeleteObjectTagsArgs.java index 1b96759aa..18e90faa2 100644 --- a/api/src/main/java/io/minio/DeleteObjectTagsArgs.java +++ b/api/src/main/java/io/minio/DeleteObjectTagsArgs.java @@ -17,11 +17,12 @@ package io.minio; /** Argument class of MinioClient.deleteObjectTags(). */ -public class DeleteObjectTagsArgs extends ObjectArgs { +public class DeleteObjectTagsArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link DeleteObjectTagsArgs}. */ - public static final class Builder extends ObjectArgs.Builder {} + public static final class Builder + extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/Directive.java b/api/src/main/java/io/minio/Directive.java new file mode 100644 index 000000000..e9f3eacc1 --- /dev/null +++ b/api/src/main/java/io/minio/Directive.java @@ -0,0 +1,23 @@ +/* + * 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; + +/** Copy object directive for metadata and tags. */ +public enum Directive { + COPY, + REPLACE; +} diff --git a/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java b/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java index 57df45b8d..066376e9a 100644 --- a/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java +++ b/api/src/main/java/io/minio/DisableObjectLegalHoldArgs.java @@ -17,12 +17,12 @@ package io.minio; /** Argument class of MinioClient.disableObjectLegalHold(). */ -public class DisableObjectLegalHoldArgs extends ObjectArgs { +public class DisableObjectLegalHoldArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link DisableObjectLegalHoldArgs}. */ public static final class Builder - extends ObjectArgs.Builder {} + extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/DownloadObjectArgs.java b/api/src/main/java/io/minio/DownloadObjectArgs.java index 72aa7f6b5..10e57a290 100644 --- a/api/src/main/java/io/minio/DownloadObjectArgs.java +++ b/api/src/main/java/io/minio/DownloadObjectArgs.java @@ -20,7 +20,7 @@ import java.nio.file.Path; import java.nio.file.Paths; -public class DownloadObjectArgs extends SsecObjectArgs { +public class DownloadObjectArgs extends ObjectReadArgs { private String fileName; public String fileName() { @@ -31,7 +31,7 @@ public static Builder builder() { return new Builder(); } - public static final class Builder extends SsecObjectArgs.Builder { + public static final class Builder extends ObjectReadArgs.Builder { public Builder fileName(String fileName) { validateFileName(fileName); operations.add(args -> args.fileName = fileName); @@ -39,13 +39,7 @@ public Builder fileName(String fileName) { } private void validateFileName(String fileName) { - if (fileName == null) { - return; - } - - if (fileName.isEmpty()) { - throw new IllegalArgumentException("filename should be either null or non-empty"); - } + validateNotEmptyString(fileName, "filename"); Path filePath = Paths.get(fileName); boolean fileExists = Files.exists(filePath); diff --git a/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java b/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java index 82f78438d..80a5a484a 100644 --- a/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java +++ b/api/src/main/java/io/minio/EnableObjectLegalHoldArgs.java @@ -17,12 +17,12 @@ package io.minio; /** Argument class of MinioClient.enableObjectLegalHold(). */ -public class EnableObjectLegalHoldArgs extends ObjectArgs { +public class EnableObjectLegalHoldArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link EnableObjectLegalHoldArgs}. */ public static final class Builder - extends ObjectArgs.Builder {} + extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectArgs.java b/api/src/main/java/io/minio/GetObjectArgs.java index ea1f85cac..a79f1088c 100644 --- a/api/src/main/java/io/minio/GetObjectArgs.java +++ b/api/src/main/java/io/minio/GetObjectArgs.java @@ -16,7 +16,7 @@ package io.minio; -public class GetObjectArgs extends SsecObjectArgs { +public class GetObjectArgs extends ObjectReadArgs { private Long offset; private Long length; @@ -32,7 +32,7 @@ public static Builder builder() { return new Builder(); } - public static final class Builder extends SsecObjectArgs.Builder { + public static final class Builder extends ObjectReadArgs.Builder { public Builder offset(Long offset) { validateOffset(offset); operations.add(args -> args.offset = offset); diff --git a/api/src/main/java/io/minio/GetObjectRetentionArgs.java b/api/src/main/java/io/minio/GetObjectRetentionArgs.java index 6d020eb84..dc76fca3d 100644 --- a/api/src/main/java/io/minio/GetObjectRetentionArgs.java +++ b/api/src/main/java/io/minio/GetObjectRetentionArgs.java @@ -17,11 +17,12 @@ package io.minio; /** Argument class of MinioClient.getObjectRetention(). */ -public class GetObjectRetentionArgs extends ObjectArgs { +public class GetObjectRetentionArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link GetObjectRetentionArgs}. */ - public static final class Builder extends ObjectArgs.Builder {} + public static final class Builder + extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetObjectTagsArgs.java b/api/src/main/java/io/minio/GetObjectTagsArgs.java index 6a85d032e..6944aa3a6 100644 --- a/api/src/main/java/io/minio/GetObjectTagsArgs.java +++ b/api/src/main/java/io/minio/GetObjectTagsArgs.java @@ -17,11 +17,11 @@ package io.minio; /** Argument class of MinioClient.getObjectTags(). */ -public class GetObjectTagsArgs extends ObjectArgs { +public class GetObjectTagsArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link GetObjectTagsArgs}. */ - public static final class Builder extends ObjectArgs.Builder {} + public static final class Builder extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java b/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java index c5d6d6483..c422671e9 100644 --- a/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java +++ b/api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java @@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit; /** Argument class of MinioClient.getPresignedObjectUrl(). */ -public class GetPresignedObjectUrlArgs extends ObjectArgs { +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); @@ -40,7 +40,8 @@ public static Builder builder() { } /** Argument builder of {@link GetPresignedObjectUrlArgs}. */ - public static final class Builder extends ObjectArgs.Builder { + public static final class Builder + extends ObjectVersionArgs.Builder { private void validateMethod(Method method) { validateNotNull(method, "method"); } diff --git a/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java b/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java index 3f4536177..1c7921b2f 100644 --- a/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java +++ b/api/src/main/java/io/minio/IsObjectLegalHoldEnabledArgs.java @@ -17,12 +17,12 @@ package io.minio; /** Argument class of MinioClient.isObjectLegalHoldEnabled(). */ -public class IsObjectLegalHoldEnabledArgs extends ObjectArgs { +public class IsObjectLegalHoldEnabledArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link IsObjectLegalHoldEnabledArgs}. */ public static final class Builder - extends ObjectArgs.Builder {} + extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/ListenBucketNotificationArgs.java b/api/src/main/java/io/minio/ListenBucketNotificationArgs.java index ca71da0d3..6e6d9d4b4 100644 --- a/api/src/main/java/io/minio/ListenBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/ListenBucketNotificationArgs.java @@ -44,9 +44,7 @@ public static Builder builder() { public static final class Builder extends BucketArgs.Builder { private void validateEvents(String[] events) { - if (events == null) { - throw new IllegalArgumentException("null events"); - } + validateNotNull(events, "events"); } protected void validate(ListenBucketNotificationArgs args) { diff --git a/api/src/main/java/io/minio/MinioClient.java b/api/src/main/java/io/minio/MinioClient.java index 13ea60baf..0aba0867e 100755 --- a/api/src/main/java/io/minio/MinioClient.java +++ b/api/src/main/java/io/minio/MinioClient.java @@ -2305,7 +2305,9 @@ public void downloadObject(DownloadObjectArgs args) * @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 use {@link #copyObject(CopyObjectArgs)} */ + @Deprecated public void copyObject( String bucketName, String objectName, @@ -2319,48 +2321,184 @@ public void copyObject( InternalException, InvalidBucketNameException, InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, ServerException, XmlParserException { - if ((bucketName == null) || (bucketName.isEmpty())) { - throw new IllegalArgumentException("bucket name cannot be empty"); + ServerSideEncryptionCustomerKey srcSsec = null; + if (srcSse instanceof ServerSideEncryptionCustomerKey) { + srcSsec = (ServerSideEncryptionCustomerKey) srcSse; } + checkReadRequestSse(srcSse); - checkObjectName(objectName); + CopyObjectArgs.Builder builder = + CopyObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .headers(headerMap) + .sse(sse) + .srcBucket(srcBucketName) + .srcObject(srcObjectName) + .srcSsec(srcSsec); - checkWriteRequestSse(sse); + if (copyConditions != null) { + Map map = copyConditions.getConditions(); + String value; + + builder.srcMatchETag(map.get("x-amz-copy-source-if-match")); + builder.srcNotMatchETag(map.get("x-amz-copy-source-if-none-match")); + + value = map.get("x-amz-copy-source-if-modified-since"); + if (value != null) { + builder.srcModifiedSince(ZonedDateTime.parse(value, Time.HTTP_HEADER_DATE_FORMAT)); + } - if ((srcBucketName == null) || (srcBucketName.isEmpty())) { - throw new IllegalArgumentException("Source bucket name cannot be empty"); + value = map.get("x-amz-copy-source-if-unmodified-since"); + if (value != null) { + builder.srcUnmodifiedSince(ZonedDateTime.parse(value, Time.HTTP_HEADER_DATE_FORMAT)); + } + + value = map.get("x-amz-metadata-directive"); + if (value != null) { + builder.metadataDirective(Directive.REPLACE); + } } + copyObject(builder.build()); + } + + /** + * Creates an object by server-side copying data from another object. + * + *
Example:{@code
+   * // Create object "my-objectname" in bucket "my-bucketname" by copying from object
+   * // "my-objectname" in bucket "my-source-bucketname".
+   * minioClient.copyObject(
+   *     CopyObjectArgs.builder()
+   *         .bucket("my-bucketname")
+   *         .object("my-objectname")
+   *         .srcBucket("my-source-bucketname")
+   *         .build());
+   *
+   * // Create object "my-objectname" in bucket "my-bucketname" by copying from object
+   * // "my-source-objectname" in bucket "my-source-bucketname".
+   * minioClient.copyObject(
+   *     CopyObjectArgs.builder()
+   *         .bucket("my-bucketname")
+   *         .object("my-objectname")
+   *         .srcBucket("my-source-bucketname")
+   *         .srcObject("my-source-objectname")
+   *         .build());
+   *
+   * // Create object "my-objectname" in bucket "my-bucketname" with server-side encryption by
+   * // copying from object "my-objectname" in bucket "my-source-bucketname".
+   * minioClient.copyObject(
+   *     CopyObjectArgs.builder()
+   *         .bucket("my-bucketname")
+   *         .object("my-objectname")
+   *         .srcBucket("my-source-bucketname")
+   *         .sse(sse)
+   *         .build());
+   *
+   * // Create object "my-objectname" in bucket "my-bucketname" by copying from SSE-C encrypted
+   * // object "my-source-objectname" in bucket "my-source-bucketname".
+   * minioClient.copyObject(
+   *     CopyObjectArgs.builder()
+   *         .bucket("my-bucketname")
+   *         .object("my-objectname")
+   *         .srcBucket("my-source-bucketname")
+   *         .srcObject("my-source-objectname")
+   *         .srcSsec(ssec)
+   *         .build());
+   *
+   * // Create object "my-objectname" in bucket "my-bucketname" with custom headers by copying from
+   * // object "my-objectname" in bucket "my-source-bucketname" using conditions.
+   * minioClient.copyObject(
+   *     CopyObjectArgs.builder()
+   *         .bucket("my-bucketname")
+   *         .object("my-objectname")
+   *         .srcBucket("my-source-bucketname")
+   *         .headers(headers)
+   *         .srcMatchETag(etag)
+   *         .build());
+   * }
+ * + * @param args {@link CopyObjectArgs} object. + * @throws ErrorResponseException thrown to indicate S3 service returned an error response. + * @throws IllegalArgumentException throws to indicate invalid argument passed. + * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. + * @throws InternalException thrown to indicate internal library error. + * @throws InvalidBucketNameException thrown to indicate invalid bucket name passed. + * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. + * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error + * response. + * @throws IOException thrown to indicate I/O error on S3 operation. + * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. + * @throws XmlParserException thrown to indicate XML parsing error. + */ + public void copyObject(CopyObjectArgs args) + throws ErrorResponseException, IllegalArgumentException, InsufficientDataException, + InternalException, InvalidBucketNameException, InvalidKeyException, + InvalidResponseException, IOException, NoSuchAlgorithmException, ServerException, + XmlParserException { + checkArgs(args); + args.validateSse(this.baseUrl); + + Multimap headers = args.genHeaders(); + // Source object name is optional, if empty default to object name. - if (srcObjectName == null) { - srcObjectName = objectName; + String srcObject = args.object(); + if (args.srcObject() != null) { + srcObject = args.srcObject(); } - checkReadRequestSse(srcSse); + String copySource = S3Escaper.encodePath("/" + args.srcBucket() + "/" + srcObject); + if (args.srcVersionId() != null) { + copySource += "?versionId=" + S3Escaper.encode(args.srcVersionId()); + } - if (headerMap == null) { - headerMap = new HashMap<>(); + headers.put("x-amz-copy-source", copySource); + + if (args.srcSsec() != null) { + headers.putAll(Multimaps.forMap(args.srcSsec().copySourceHeaders())); + } + + if (args.srcMatchETag() != null) { + headers.put("x-amz-copy-source-if-match", args.srcMatchETag()); } - headerMap.put("x-amz-copy-source", S3Escaper.encodePath(srcBucketName + "/" + srcObjectName)); + if (args.srcNotMatchETag() != null) { + headers.put("x-amz-copy-source-if-none-match", args.srcNotMatchETag()); + } - if (sse != null) { - headerMap.putAll(sse.headers()); + if (args.srcModifiedSince() != null) { + headers.put( + "x-amz-copy-source-if-modified-since", + args.srcModifiedSince().format(Time.HTTP_HEADER_DATE_FORMAT)); } - if (srcSse != null) { - headerMap.putAll(srcSse.copySourceHeaders()); + if (args.srcUnmodifiedSince() != null) { + headers.put( + "x-amz-copy-source-if-unmodified-since", + args.srcUnmodifiedSince().format(Time.HTTP_HEADER_DATE_FORMAT)); } - if (copyConditions != null) { - headerMap.putAll(copyConditions.getConditions()); + if (args.metadataDirective() != null) { + headers.put("x-amz-metadata-directive", args.metadataDirective().name()); } - Response response = executePut(bucketName, objectName, headerMap, null, "", 0); + if (args.taggingDirective() != null) { + headers.put("x-amz-tagging-directive", args.taggingDirective().name()); + } - try (ResponseBody body = response.body()) { + try (Response response = + execute( + Method.PUT, + args.bucket(), + args.object(), + getRegion(args.bucket()), + headers, + null, + null, + 0)) { // For now ignore the copyObjectResult, just read and parse it. - Xml.unmarshal(CopyObjectResult.class, body.charStream()); + Xml.unmarshal(CopyObjectResult.class, response.body().charStream()); } } @@ -4942,29 +5080,119 @@ public void putObject( * @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 use {@link #putObject(PutObjectArgs)} */ + @Deprecated public void putObject( String bucketName, String objectName, InputStream stream, PutObjectOptions options) throws ErrorResponseException, IllegalArgumentException, InsufficientDataException, InternalException, InvalidBucketNameException, InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, ServerException, XmlParserException { - checkBucketName(bucketName); - checkObjectName(objectName); + putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + stream, options.objectSize(), options.partSize()) + .contentType(options.contentType()) + .headers(options.headers()) + .sse(options.sse()) + .build()); + } - if (stream == null) { - throw new IllegalArgumentException("InputStream must be provided"); - } + /** + * Uploads data from a stream to an object. + * + *
Example:{@code
+   * minioClient.putObject(
+   *     PutObjectArgs.builder()
+   *         .bucket("my-bucketname")
+   *         .object("my-objectname")
+   *         .stream(stream, 7003256, -1)
+   *         .build());
+   * }
+ * + * @param args {@link PutObjectArgs} object. + * @throws ErrorResponseException thrown to indicate S3 service returned an error response. + * @throws IllegalArgumentException throws to indicate invalid argument passed. + * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. + * @throws InternalException thrown to indicate internal library error. + * @throws InvalidBucketNameException thrown to indicate invalid bucket name passed. + * @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library. + * @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error + * response. + * @throws IOException thrown to indicate I/O error on S3 operation. + * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. + * @throws XmlParserException thrown to indicate XML parsing error. + */ + public void putObject(PutObjectArgs args) + throws ErrorResponseException, IllegalArgumentException, InsufficientDataException, + InternalException, InvalidBucketNameException, InvalidKeyException, + InvalidResponseException, IOException, NoSuchAlgorithmException, ServerException, + XmlParserException { + checkArgs(args); + args.validateSse(this.baseUrl); - if (options == null) { - throw new IllegalArgumentException("PutObjectOptions must be provided"); - } + BufferedInputStream data = args.stream(); - if (!(stream instanceof BufferedInputStream)) { - stream = new BufferedInputStream(stream); - } + Multimap headers = HashMultimap.create(); + headers.putAll(args.extraHeaders()); + headers.putAll(args.genHeaders()); + headers.put("Content-Type", args.contentType()); + + // initiate new multipart upload. + String uploadId = + createMultipartUpload( + args.bucket(), args.region(), args.object(), headers, args.extraQueryParams()); + + long uploadedSize = 0L; + int partCount = args.partCount(); + Part[] totalParts = new Part[PutObjectOptions.MAX_MULTIPART_COUNT]; + + try { + for (int partNumber = 1; partNumber <= partCount || partCount < 0; partNumber++) { + long availableSize = args.partSize(); + if (partCount > 0) { + if (partNumber == partCount) { + availableSize = args.objectSize() - uploadedSize; + } + } else { + availableSize = getAvailableSize(data, args.partSize() + 1); + + // If availableSize is less or equal to args.partSize(), then we have reached last + // part. + if (availableSize <= args.partSize()) { + partCount = partNumber; + } else { + availableSize = args.partSize(); + } + } + + Map ssecHeaders = null; + // set encryption headers in the case of SSE-C. + if (args.sse() != null && args.sse().type() == ServerSideEncryption.Type.SSE_C) { + ssecHeaders = args.sse().headers(); + } - putObject(bucketName, objectName, options, stream); + String etag = + uploadPart( + args.bucket(), + args.object(), + data, + (int) availableSize, + uploadId, + partNumber, + ssecHeaders); + totalParts[partNumber - 1] = new Part(partNumber, etag); + uploadedSize += availableSize; + } + + completeMultipartUpload(args.bucket(), args.object(), uploadId, totalParts); + } catch (RuntimeException e) { + abortMultipartUpload(args.bucket(), args.object(), uploadId); + throw e; + } catch (Exception e) { + abortMultipartUpload(args.bucket(), args.object(), uploadId); + throw e; + } } /** @@ -7074,24 +7302,71 @@ protected void completeMultipartUpload( * @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library. * @throws XmlParserException thrown to indicate XML parsing error. */ + @Deprecated protected String createMultipartUpload( String bucketName, String objectName, Map headerMap) throws InvalidBucketNameException, IllegalArgumentException, NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException { + return createMultipartUpload(bucketName, null, objectName, Multimaps.forMap(headerMap), null); + } + + /** + * Do CreateMultipartUpload + * S3 API. + * + * @param bucketName Name of the bucket. + * @param objectName Object name in the bucket. + * @param headers Request headers. + * @return String - Contains upload ID. + * @throws ErrorResponseException thrown to indicate S3 service returned an error response. + * @throws IllegalArgumentException throws to indicate invalid argument passed. + * @throws InsufficientDataException thrown to indicate not enough data available in InputStream. + * @throws InternalException thrown to indicate internal library error. + * @throws InvalidBucketNameException thrown to indicate invalid bucket name passed. + * @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. + */ + protected String createMultipartUpload( + String bucketName, + String region, + String objectName, + Multimap headers, + Multimap queryParams) + throws InvalidBucketNameException, IllegalArgumentException, NoSuchAlgorithmException, + InsufficientDataException, IOException, InvalidKeyException, ServerException, + XmlParserException, ErrorResponseException, InternalException, InvalidResponseException { + Multimap queryParamsCopy = HashMultimap.create(); + if (queryParams != null) { + queryParamsCopy.putAll(queryParams); + } + queryParamsCopy.put("uploads", ""); + + Multimap headersCopy = HashMultimap.create(); + headersCopy.putAll(headers); // set content type if not set already - if ((headerMap != null) && (headerMap.get("Content-Type") == null)) { - headerMap.put("Content-Type", "application/octet-stream"); + if (headersCopy.get("Content-Type") == null) { + headersCopy.put("Content-Type", "application/octet-stream"); } - Map queryParamMap = new HashMap<>(); - queryParamMap.put("uploads", ""); + if (region == null) { + region = this.region; + } - Response response = executePost(bucketName, objectName, headerMap, queryParamMap, ""); + if (region == null) { + region = getRegion(bucketName); + } - try (ResponseBody body = response.body()) { + try (Response response = + execute( + Method.POST, bucketName, objectName, region, headersCopy, queryParamsCopy, null, 0)) { InitiateMultipartUploadResult result = - Xml.unmarshal(InitiateMultipartUploadResult.class, body.charStream()); + Xml.unmarshal(InitiateMultipartUploadResult.class, response.body().charStream()); return result.uploadId(); } } diff --git a/api/src/main/java/io/minio/ObjectArgs.java b/api/src/main/java/io/minio/ObjectArgs.java index 02eb41827..a1d0592e8 100644 --- a/api/src/main/java/io/minio/ObjectArgs.java +++ b/api/src/main/java/io/minio/ObjectArgs.java @@ -16,44 +16,44 @@ package io.minio; +import okhttp3.HttpUrl; + /** Base argument class holds object name and version ID along with bucket information. */ public abstract class ObjectArgs extends BucketArgs { protected String objectName; - protected String versionId; public String object() { return objectName; } - public String versionId() { - return versionId; + protected void checkSse(ServerSideEncryption sse, HttpUrl url) { + if (sse == null) { + return; + } + + if (sse.type().requiresTls() && !url.isHttps()) { + throw new IllegalArgumentException( + sse.type().name() + "operations must be performed over a secure connection."); + } } /** Base argument builder class for {@link ObjectArgs}. */ public abstract static class Builder, A extends ObjectArgs> extends BucketArgs.Builder { - private void validateName(String name) { - if (name == null || name.isEmpty()) { - throw new IllegalArgumentException("object name must be non-null/non-empty string"); - } + protected void validateObjectName(String name) { + validateNotEmptyString(name, "object name"); } protected void validate(A args) { super.validate(args); - validateName(args.objectName); + validateObjectName(args.objectName); } @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class public B object(String name) { - validateName(name); + validateObjectName(name); operations.add(args -> args.objectName = name); return (B) this; } - - @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class - public B versionId(String versionId) { - operations.add(args -> args.versionId = versionId); - return (B) this; - } } } diff --git a/api/src/main/java/io/minio/SsecObjectArgs.java b/api/src/main/java/io/minio/ObjectReadArgs.java similarity index 72% rename from api/src/main/java/io/minio/SsecObjectArgs.java rename to api/src/main/java/io/minio/ObjectReadArgs.java index 9e0ed3514..5b0cf1a24 100644 --- a/api/src/main/java/io/minio/SsecObjectArgs.java +++ b/api/src/main/java/io/minio/ObjectReadArgs.java @@ -18,26 +18,19 @@ import okhttp3.HttpUrl; -public abstract class SsecObjectArgs extends ObjectArgs { +public abstract class ObjectReadArgs extends ObjectVersionArgs { protected ServerSideEncryptionCustomerKey ssec; public ServerSideEncryptionCustomerKey ssec() { return ssec; } - protected void validateSsec(HttpUrl baseUrl) { - if (ssec == null) { - return; - } - - if (ssec.type().requiresTls() && !baseUrl.isHttps()) { - throw new IllegalArgumentException( - ssec.type().name() + "operations must be performed over a secure connection."); - } + protected void validateSsec(HttpUrl url) { + checkSse(ssec, url); } - public abstract static class Builder, A extends SsecObjectArgs> - extends ObjectArgs.Builder { + 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) { operations.add(args -> args.ssec = ssec); diff --git a/api/src/main/java/io/minio/ObjectVersionArgs.java b/api/src/main/java/io/minio/ObjectVersionArgs.java new file mode 100644 index 000000000..1a651e8fd --- /dev/null +++ b/api/src/main/java/io/minio/ObjectVersionArgs.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** Base argument class holds object name and version ID along with bucket information. */ +public abstract class ObjectVersionArgs extends ObjectArgs { + protected String versionId; + + public String versionId() { + return versionId; + } + + /** Base argument builder class for {@link ObjectVersionArgs}. */ + public abstract static class Builder, A extends ObjectVersionArgs> + extends ObjectArgs.Builder { + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B versionId(String versionId) { + operations.add(args -> args.versionId = versionId); + return (B) this; + } + } +} diff --git a/api/src/main/java/io/minio/ObjectWriteArgs.java b/api/src/main/java/io/minio/ObjectWriteArgs.java new file mode 100644 index 000000000..7fa9a936b --- /dev/null +++ b/api/src/main/java/io/minio/ObjectWriteArgs.java @@ -0,0 +1,169 @@ +/* + * 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.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import io.minio.messages.Retention; +import io.minio.messages.Tags; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +import okhttp3.HttpUrl; + +public abstract class ObjectWriteArgs extends ObjectArgs { + protected Multimap headers = + Multimaps.unmodifiableMultimap(HashMultimap.create()); + protected Multimap userMetadata = + Multimaps.unmodifiableMultimap(HashMultimap.create()); + protected ServerSideEncryption sse; + protected Tags tags = new Tags(); + protected Retention retention; + protected boolean legalHold; + + public Multimap headers() { + return headers; + } + + public Multimap userMetadata() { + return userMetadata; + } + + public ServerSideEncryption sse() { + return sse; + } + + public Tags tags() { + return tags; + } + + public Retention retention() { + return retention; + } + + public boolean legalHold() { + return legalHold; + } + + public Multimap genHeaders() { + Multimap headers = HashMultimap.create(); + + headers.putAll(this.headers); + headers.putAll(userMetadata); + + if (sse != null) { + headers.putAll(Multimaps.forMap(sse.headers())); + } + + String tagging = + tags.get().entrySet().stream() + .map(e -> S3Escaper.encode(e.getKey()) + "=" + S3Escaper.encode(e.getValue())) + .collect(Collectors.joining("&")); + if (!tagging.isEmpty()) { + headers.put("x-amz-tagging", tagging); + } + + if (retention != null && retention.mode() != null) { + headers.put("x-amz-object-lock-mode", retention.mode().name()); + headers.put( + "x-amz-object-lock-retain-until-date", + retention.retainUntilDate().format(Time.HTTP_HEADER_DATE_FORMAT)); + } + + if (legalHold) { + headers.put("x-amz-object-lock-legal-hold", "ON"); + } + + return headers; + } + + protected void validateSse(HttpUrl url) { + checkSse(sse, url); + } + + public abstract static class Builder, A extends ObjectWriteArgs> + extends ObjectArgs.Builder { + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B headers(Map headers) { + final Multimap headersCopy = toMultimap(headers); + operations.add(args -> args.headers = headersCopy); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B headers(Multimap headers) { + final Multimap headersCopy = copyMultimap(headers); + operations.add(args -> args.headers = headersCopy); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B userMetadata(Map userMetadata) { + return userMetadata((userMetadata == null) ? null : Multimaps.forMap(userMetadata)); + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B userMetadata(Multimap userMetadata) { + Multimap userMetadataCopy = HashMultimap.create(); + if (userMetadata != null) { + for (String key : userMetadata.keySet()) { + userMetadataCopy.putAll( + (key.toLowerCase(Locale.US).startsWith("x-amz-meta-") ? "" : "x-amz-meta-") + key, + userMetadata.get(key)); + } + } + + final Multimap finalUserMetadata = + Multimaps.unmodifiableMultimap(userMetadataCopy); + operations.add(args -> args.userMetadata = finalUserMetadata); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B sse(ServerSideEncryption sse) { + operations.add(args -> args.sse = sse); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B tags(Map map) { + final Tags tags = (map == null) ? new Tags() : Tags.newObjectTags(map); + operations.add(args -> args.tags = tags); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B tags(Tags tags) { + Tags tagsCopy = (tags == null) ? new Tags() : Tags.newObjectTags(tags.get()); + operations.add(args -> args.tags = tagsCopy); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B retention(Retention retention) { + operations.add(args -> args.retention = retention); + return (B) this; + } + + @SuppressWarnings("unchecked") // Its safe to type cast to B as B is inherited by this class + public B legalHold(boolean flag) { + operations.add(args -> args.legalHold = flag); + return (B) this; + } + } +} diff --git a/api/src/main/java/io/minio/PutObjectArgs.java b/api/src/main/java/io/minio/PutObjectArgs.java new file mode 100644 index 000000000..87ef95b41 --- /dev/null +++ b/api/src/main/java/io/minio/PutObjectArgs.java @@ -0,0 +1,164 @@ +/* + * 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.io.BufferedInputStream; +import java.io.InputStream; + +/** Argument class of MinioClient.putObject(). */ +public class PutObjectArgs extends ObjectWriteArgs { + private BufferedInputStream stream; + private long objectSize; + private long partSize; + private int partCount; + private String contentType; + + public BufferedInputStream stream() { + return stream; + } + + public long objectSize() { + return objectSize; + } + + public long partSize() { + return partSize; + } + + public int partCount() { + return partCount; + } + + /** + * Gets content type. It returns if content type is set (or) value of "Content-Type" header (or) + * default "application/octet-stream". + */ + public String contentType() { + if (contentType != null) { + return contentType; + } + + if (!this.headers().containsKey("Content-Type")) { + return "application/octet-stream"; + } + + return this.headers().get("Content-Type").iterator().next(); + } + + public static Builder builder() { + return new Builder(); + } + + /** Argument builder of {@link PutObjectArgs}. */ + public static final class Builder extends ObjectWriteArgs.Builder { + @Override + protected void validate(PutObjectArgs args) { + super.validate(args); + validateNotNull(args.stream, "stream"); + } + + /** + * Sets stream to upload. Two ways to provide object/part sizes. + * + *
    + *
  • If object size is unknown, pass -1 to objectSize and pass valid partSize. + *
  • If object size is known, pass -1 to partSize for auto detect; else pass valid partSize + * to control memory usage and no. of parts in upload. + *
  • If partSize is greater than objectSize, objectSize is used as partSize. + *
+ * + *

A valid part size is between 5MiB to 5GiB (both limits inclusive). + */ + public Builder stream(InputStream stream, long objectSize, long partSize) { + validateNotNull(stream, "stream"); + + int partCount = -1; + + if (partSize > 0) { + if (partSize < PutObjectOptions.MIN_MULTIPART_SIZE) { + throw new IllegalArgumentException( + "part size " + partSize + " is not supported; minimum allowed 5MiB"); + } + + if (partSize > PutObjectOptions.MAX_PART_SIZE) { + throw new IllegalArgumentException( + "part size " + partSize + " is not supported; maximum allowed 5GiB"); + } + } + + if (objectSize >= 0) { + if (objectSize > PutObjectOptions.MAX_OBJECT_SIZE) { + throw new IllegalArgumentException( + "object size " + objectSize + " is not supported; maximum allowed 5TiB"); + } + + if (partSize > 0) { + if (partSize > objectSize) { + partSize = objectSize; + } + + partCount = (int) Math.ceil((double) objectSize / partSize); + if (partCount > PutObjectOptions.MAX_MULTIPART_COUNT) { + throw new IllegalArgumentException( + "object size " + + objectSize + + " and part size " + + partSize + + " make more than " + + PutObjectOptions.MAX_MULTIPART_COUNT + + "parts for upload"); + } + } else { + double pSize = Math.ceil((double) objectSize / PutObjectOptions.MAX_MULTIPART_COUNT); + pSize = + Math.ceil(pSize / PutObjectOptions.MIN_MULTIPART_SIZE) + * PutObjectOptions.MIN_MULTIPART_SIZE; + + partSize = (long) pSize; + + if (pSize > 0) { + partCount = (int) Math.ceil(objectSize / pSize); + } else { + partCount = 1; + } + } + } else if (partSize <= 0) { + throw new IllegalArgumentException( + "valid part size must be provided when object size is unknown"); + } + + final BufferedInputStream bis = + (stream instanceof BufferedInputStream) + ? (BufferedInputStream) stream + : new BufferedInputStream(stream); + final long finalPartSize = partSize; + final int finalPartCount = partCount; + + operations.add(args -> args.stream = bis); + operations.add(args -> args.objectSize = objectSize); + operations.add(args -> args.partSize = finalPartSize); + operations.add(args -> args.partCount = finalPartCount); + return this; + } + + public Builder contentType(String contentType) { + validateNotEmptyString(contentType, "content type"); + operations.add(args -> args.contentType = contentType); + return this; + } + } +} diff --git a/api/src/main/java/io/minio/RemoveIncompleteUploadArgs.java b/api/src/main/java/io/minio/RemoveIncompleteUploadArgs.java index 7b132bf71..62f6668af 100644 --- a/api/src/main/java/io/minio/RemoveIncompleteUploadArgs.java +++ b/api/src/main/java/io/minio/RemoveIncompleteUploadArgs.java @@ -17,12 +17,12 @@ package io.minio; -public class RemoveIncompleteUploadArgs extends ObjectArgs { +public class RemoveIncompleteUploadArgs extends ObjectVersionArgs { public static Builder builder() { return new Builder(); } public static final class Builder - extends ObjectArgs.Builder {} + extends ObjectVersionArgs.Builder {} } diff --git a/api/src/main/java/io/minio/RemoveObjectArgs.java b/api/src/main/java/io/minio/RemoveObjectArgs.java index a59e06aa2..b36465b3e 100644 --- a/api/src/main/java/io/minio/RemoveObjectArgs.java +++ b/api/src/main/java/io/minio/RemoveObjectArgs.java @@ -17,7 +17,7 @@ package io.minio; /** Argument class of MinioClient.removeObject(). */ -public class RemoveObjectArgs extends ObjectArgs { +public class RemoveObjectArgs extends ObjectVersionArgs { private boolean bypassGovernanceMode; public boolean bypassGovernanceMode() { @@ -29,7 +29,7 @@ public static Builder builder() { } /** Argument builder of {@link RemoveObjectArgs}. */ - public static final class Builder extends ObjectArgs.Builder { + public static final class Builder extends ObjectVersionArgs.Builder { public Builder bypassGovernanceMode(boolean flag) { operations.add(args -> args.bypassGovernanceMode = flag); return this; diff --git a/api/src/main/java/io/minio/SelectObjectContentArgs.java b/api/src/main/java/io/minio/SelectObjectContentArgs.java index beeda3a1b..0c6674929 100644 --- a/api/src/main/java/io/minio/SelectObjectContentArgs.java +++ b/api/src/main/java/io/minio/SelectObjectContentArgs.java @@ -20,7 +20,7 @@ import io.minio.messages.InputSerialization; import io.minio.messages.OutputSerialization; -public class SelectObjectContentArgs extends SsecObjectArgs { +public class SelectObjectContentArgs extends ObjectReadArgs { private String sqlExpression; private InputSerialization inputSerialization; private OutputSerialization outputSerialization; @@ -57,7 +57,7 @@ public static Builder builder() { } public static final class Builder - extends SsecObjectArgs.Builder { + extends ObjectReadArgs.Builder { private void validateSqlExpression(String se) { validateNotEmptyString(se, "sqlExpression"); } diff --git a/api/src/main/java/io/minio/SetBucketEncryptionArgs.java b/api/src/main/java/io/minio/SetBucketEncryptionArgs.java index 28ffab374..f2134729d 100644 --- a/api/src/main/java/io/minio/SetBucketEncryptionArgs.java +++ b/api/src/main/java/io/minio/SetBucketEncryptionArgs.java @@ -33,9 +33,7 @@ public static Builder builder() { /** Argument builder of {@link SetBucketEncryptionArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(SseConfiguration config) { - if (config == null) { - throw new IllegalArgumentException("null server-side encryption configuration"); - } + 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 d8cb2f074..de2c936c2 100644 --- a/api/src/main/java/io/minio/SetBucketLifeCycleArgs.java +++ b/api/src/main/java/io/minio/SetBucketLifeCycleArgs.java @@ -31,9 +31,7 @@ public static Builder builder() { /** Argument builder of {@link SetBucketLifeCycleArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(String config) { - if (config == null || config.isEmpty()) { - throw new IllegalArgumentException("empty life-cycle configuration"); - } + validateNotEmptyString(config, "life-cycle 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 730065677..708e4d45d 100644 --- a/api/src/main/java/io/minio/SetBucketNotificationArgs.java +++ b/api/src/main/java/io/minio/SetBucketNotificationArgs.java @@ -33,9 +33,7 @@ public static Builder builder() { /** Argument builder of {@link SetBucketNotificationArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(NotificationConfiguration config) { - if (config == null) { - throw new IllegalArgumentException("null notification configuration"); - } + 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 0c20c4058..2055b5522 100644 --- a/api/src/main/java/io/minio/SetBucketPolicyArgs.java +++ b/api/src/main/java/io/minio/SetBucketPolicyArgs.java @@ -31,9 +31,7 @@ public static Builder builder() { /** Argument builder of {@link SetBucketPolicyArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(String config) { - if (config == null) { - throw new IllegalArgumentException("null policy configuration"); - } + validateNotNull(config, "policy configuration"); } @Override diff --git a/api/src/main/java/io/minio/SetBucketTagsArgs.java b/api/src/main/java/io/minio/SetBucketTagsArgs.java index fb67727bc..b4e31fb56 100644 --- a/api/src/main/java/io/minio/SetBucketTagsArgs.java +++ b/api/src/main/java/io/minio/SetBucketTagsArgs.java @@ -34,9 +34,7 @@ public static Builder builder() { /** Argument builder of {@link SetBucketTagsArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateTags(Tags tags) { - if (tags == null) { - throw new IllegalArgumentException("null tags to set"); - } + validateNotNull(tags, "tags"); } protected void validate(SetBucketTagsArgs args) { @@ -45,10 +43,7 @@ protected void validate(SetBucketTagsArgs args) { } public Builder tags(Map map) { - if (map == null) { - throw new IllegalArgumentException("null map for tags"); - } - + validateNotNull(map, "map for tags"); operations.add(args -> args.tags = Tags.newBucketTags(map)); return this; } diff --git a/api/src/main/java/io/minio/SetDefaultRetentionArgs.java b/api/src/main/java/io/minio/SetDefaultRetentionArgs.java index dcf84e9e6..ccc3f4afd 100644 --- a/api/src/main/java/io/minio/SetDefaultRetentionArgs.java +++ b/api/src/main/java/io/minio/SetDefaultRetentionArgs.java @@ -33,9 +33,7 @@ public static Builder builder() { /** Argument builder of {@link SetDefaultRetentionArgs}. */ public static final class Builder extends BucketArgs.Builder { private void validateConfig(ObjectLockConfiguration config) { - if (config == null) { - throw new IllegalArgumentException("null object-lock configuration"); - } + 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 a3cb1fa10..140906519 100644 --- a/api/src/main/java/io/minio/SetObjectRetentionArgs.java +++ b/api/src/main/java/io/minio/SetObjectRetentionArgs.java @@ -19,7 +19,7 @@ import io.minio.messages.Retention; /** Argument class of MinioClient.setObjectRetention(). */ -public class SetObjectRetentionArgs extends ObjectArgs { +public class SetObjectRetentionArgs extends ObjectVersionArgs { private Retention config; private boolean bypassGovernanceMode; @@ -36,11 +36,10 @@ public static Builder builder() { } /** Argument builder of {@link SetObjectRetentionArgs}. */ - public static final class Builder extends ObjectArgs.Builder { + public static final class Builder + extends ObjectVersionArgs.Builder { private void validateConfig(Retention config) { - if (config == null) { - throw new IllegalArgumentException("empty retention configuration"); - } + 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 80b6232eb..afc62a6ea 100644 --- a/api/src/main/java/io/minio/SetObjectTagsArgs.java +++ b/api/src/main/java/io/minio/SetObjectTagsArgs.java @@ -20,7 +20,7 @@ import java.util.Map; /** Argument class of MinioClient.setObjectTags(). */ -public class SetObjectTagsArgs extends ObjectArgs { +public class SetObjectTagsArgs extends ObjectVersionArgs { private Tags tags; public Tags tags() { @@ -32,11 +32,9 @@ public static Builder builder() { } /** Argument builder of {@link SetObjectTagsArgs}. */ - public static final class Builder extends ObjectArgs.Builder { + public static final class Builder extends ObjectVersionArgs.Builder { private void validateTags(Tags tags) { - if (tags == null) { - throw new IllegalArgumentException("null tags to set"); - } + validateNotNull(tags, "tags"); } protected void validate(SetObjectTagsArgs args) { @@ -45,10 +43,7 @@ protected void validate(SetObjectTagsArgs args) { } public Builder tags(Map map) { - if (map == null) { - throw new IllegalArgumentException("null map for tags"); - } - + validateNotNull(map, "map for tags"); operations.add(args -> args.tags = Tags.newObjectTags(map)); return this; } diff --git a/api/src/main/java/io/minio/StatObjectArgs.java b/api/src/main/java/io/minio/StatObjectArgs.java index c1613531a..83d7820fa 100644 --- a/api/src/main/java/io/minio/StatObjectArgs.java +++ b/api/src/main/java/io/minio/StatObjectArgs.java @@ -17,11 +17,11 @@ package io.minio; /** Argument class of MinioClient.statObject(). */ -public class StatObjectArgs extends SsecObjectArgs { +public class StatObjectArgs extends ObjectReadArgs { public static Builder builder() { return new Builder(); } /** Argument builder of {@link StatObjectArgs}. */ - public static final class Builder extends SsecObjectArgs.Builder {} + public static final class Builder extends ObjectReadArgs.Builder {} } diff --git a/api/src/test/java/io/minio/MinioClientTest.java b/api/src/test/java/io/minio/MinioClientTest.java index 0054b3ae8..2228d5f4a 100644 --- a/api/src/test/java/io/minio/MinioClientTest.java +++ b/api/src/test/java/io/minio/MinioClientTest.java @@ -326,24 +326,28 @@ public void testReadSse1() @Test(expected = IllegalArgumentException.class) public void testWriteSse1() throws NoSuchAlgorithmException, IOException, InvalidKeyException, MinioException { + MinioClient client = new MinioClient("http://play.min.io:9000"); KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); - PutObjectOptions options = new PutObjectOptions(0, -1); - options.setSse(ServerSideEncryption.withCustomerKey(keyGen.generateKey())); - MinioClient client = new MinioClient("http://play.min.io:9000"); - client.putObject("mybucket", "myobject", new ByteArrayInputStream(new byte[] {}), options); + client.putObject( + PutObjectArgs.builder().bucket("mybucket").object("myobject").stream( + new ByteArrayInputStream(new byte[] {}), 0, -1) + .sse(ServerSideEncryption.withCustomerKey(keyGen.generateKey())) + .build()); Assert.fail("exception should be thrown"); } @Test(expected = IllegalArgumentException.class) public void testWriteSse2() throws NoSuchAlgorithmException, IOException, InvalidKeyException, MinioException { + MinioClient client = new MinioClient("http://play.min.io:9000"); Map myContext = new HashMap<>(); myContext.put("key1", "value1"); - PutObjectOptions options = new PutObjectOptions(0, -1); - options.setSse(ServerSideEncryption.withManagedKeys("keyId", myContext)); - MinioClient client = new MinioClient("http://play.min.io:9000"); - client.putObject("mybucket", "myobject", new ByteArrayInputStream(new byte[] {}), options); + client.putObject( + PutObjectArgs.builder().bucket("mybucket").object("myobject").stream( + new ByteArrayInputStream(new byte[] {}), 0, -1) + .sse(ServerSideEncryption.withManagedKeys("keyId", myContext)) + .build()); Assert.fail("exception should be thrown"); } diff --git a/docs/API.md b/docs/API.md index 8f02578fa..a7a5f8cbd 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1017,45 +1017,69 @@ minioClient.composeObject("my-bucketname", "my-objectname", sourceObjectList, us ``` -### copyObject(String bucketName, String objectName, Map headerMap, ServerSideEncryption sse, String srcBucketName, String srcObjectName, ServerSideEncryption srcSse, CopyConditions copyConditions) -`public void copyObject(String bucketName, String objectName, Map headerMap, ServerSideEncryption sse, String srcBucketName, String srcObjectName, ServerSideEncryption srcSse, CopyConditions copyConditions)` _[[Javadoc]](http://minio.github.io/minio-java/io/minio/MinioClient.html#copyObject-java.lang.String-java.lang.String-java.util.Map-io.minio.ServerSideEncryption-java.lang.String-java.lang.String-io.minio.ServerSideEncryption-io.minio.CopyConditions-)_ +### copyObject(CopyObjectArgs args) +`public void copyObject(CopyObjectArgs args)` _[[Javadoc]](http://minio.github.io/minio-java/io/minio/MinioClient.html#copyObject-io.minio.CopyObjectArgs-)_ Creates an object by server-side copying data from another object. __Parameters__ -| Parameter | Type | Description | -|:-------------------|:-------------------------|:---------------------------------------------------------------| -| ``bucketName`` | _String_ | Name of the bucket. | -| ``objectName`` | _String_ | Object name to be created. | -| ``headerMap`` | _Map_ | (Optional) User metadata. | -| ``sse`` | _[ServerSideEncryption]_ | (Optional) Server-side encryption. | -| ``srcBucketName`` | _String_ | Source bucket name. | -| ``srcObjectName`` | _String_ | (Optional) Source object name. | -| ``srcSse`` | _[ServerSideEncryption]_ | (Optional) SSE-C type server-side encryption of source object. | -| ``copyConditions`` | _[CopyConditions]_ | (Optional) Conditiions to be used in copy operation. | +| Parameter | Type | Description | +|:----------|:-------------------|:------------| +| ``args`` | _[CopyObjectArgs]_ | Arguments. | __Example__ ```java -// Copy data from my-source-bucketname/my-objectname to my-bucketname/my-objectname. -minioClient.copyObject("my-bucketname", "my-objectname", null, null, "my-source-bucketname", null, null, - null); +// Create object "my-objectname" in bucket "my-bucketname" by copying from object +// "my-objectname" in bucket "my-source-bucketname". +minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .build()); -// Copy data from my-source-bucketname/my-source-objectname to my-bucketname/my-objectname. -minioClient.copyObject("my-bucketname", "my-objectname", null, null, "my-source-bucketname", - "my-source-objectname", null, null); +// Create object "my-objectname" in bucket "my-bucketname" by copying from object +// "my-source-objectname" in bucket "my-source-bucketname". +minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .srcObject("my-source-objectname") + .build()); -// Copy data from my-source-bucketname/my-objectname to my-bucketname/my-objectname by server-side encryption. -minioClient.copyObject("my-bucketname", "my-objectname", null, sse, "my-source-bucketname", null, null, null); +// Create object "my-objectname" in bucket "my-bucketname" with server-side encryption by +// copying from object "my-objectname" in bucket "my-source-bucketname". +minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .sse(sse) + .build()); -// Copy data from SSE-C encrypted my-source-bucketname/my-objectname to my-bucketname/my-objectname. -minioClient.copyObject("my-bucketname", "my-objectname", null, null, "my-source-bucketname", null, srcSsec, - null); +// Create object "my-objectname" in bucket "my-bucketname" by copying from SSE-C encrypted +// object "my-source-objectname" in bucket "my-source-bucketname". +minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .srcObject("my-source-objectname") + .srcSsec(ssec) + .build()); -// Copy data from my-source-bucketname/my-objectname to my-bucketname/my-objectname with user metadata and -// copy conditions. -minioClient.copyObject("my-bucketname", "my-objectname", headers, null, "my-source-bucketname", null, null, - conditions); +// Create object "my-objectname" in bucket "my-bucketname" with custom headers by copying from +// object "my-objectname" in bucket "my-source-bucketname" using conditions. +minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .headers(headers) + .srcMatchETag(etag) + .build()); ``` @@ -1744,3 +1768,4 @@ ObjectStat objectStat = [DeleteDefaultRetentionArgs]: http://minio.github.io/minio-java/io/minio/DeleteDefaultRetentionArgs.html [RemoveIncompleteUploadArgs]: http://minio.github.io/minio-java/io/minio/RemoveIncompleteUploadArgs.html [GetPresignedObjectUrlArgs]: http://minio.github.io/minio-java/io/minio/GetPresignedObjectUrlArgs.html +[CopyObjectArgs]: http://minio.github.io/minio-java/io/minio/CopyObjectArgs.html diff --git a/examples/CopyObject.java b/examples/CopyObject.java index 5d97544e1..610361060 100644 --- a/examples/CopyObject.java +++ b/examples/CopyObject.java @@ -15,13 +15,17 @@ * limitations under the License. */ +import io.minio.CopyObjectArgs; import io.minio.MinioClient; -import io.minio.PutObjectOptions; +import io.minio.ServerSideEncryption; +import io.minio.ServerSideEncryptionCustomerKey; import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.KeyGenerator; public class CopyObject { /** MinioClient.copyObject() example. */ @@ -39,52 +43,130 @@ public static void main(String[] args) // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", // "YOUR-SECRETACCESSKEY"); - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryptionCustomerKey ssec = + ServerSideEncryption.withCustomerKey(keyGen.generateKey()); + + Map myContext = new HashMap<>(); + myContext.put("key1", "value1"); + ServerSideEncryption sseKms = ServerSideEncryption.withManagedKeys("Key-Id", myContext); + + ServerSideEncryption sseS3 = ServerSideEncryption.atRest(); + + String versionId = "ac38316c-fe14-4f96-9f76-8f675ae5a79e"; + + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + headers.put("x-amz-meta-my-project", "Project One"); + + String etag = "9855d05ab7a1cfd5ea304f0547c24496"; + + { + // Create object "my-objectname" in bucket "my-bucketname" by copying from object + // "my-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .build()); + System.out.println( + "my-source-bucketname/my-objectname copied " + + "to my-bucketname/my-objectname successfully"); + } + + { + // Create object "my-objectname" in bucket "my-bucketname" by copying from object + // "my-source-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .srcObject("my-source-objectname") + .build()); + System.out.println( + "my-source-bucketname/my-source-objectname copied " + + "to my-bucketname/my-objectname successfully"); } - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. - minioClient.putObject( - "my-bucketname", "my-objectname", bais, new PutObjectOptions(bais.available(), -1)); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - - minioClient.copyObject( - "my-destbucketname", - "my-objectname-copy", - null, - null, - "my-bucketname", - "my-objectname", - null, - null); - System.out.println("my-objectname-copy copied to my-destbucketname successfully"); + { + // Create object "my-objectname" in bucket "my-bucketname" with SSE-KMS server-side + // encryption by copying from object "my-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .sse(sseKms) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-objectname copied " + + "to my-bucketname/my-objectname successfully"); + } + + { + // Create object "my-objectname" in bucket "my-bucketname" with SSE-S3 server-side + // encryption by copying from object "my-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .sse(sseS3) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-objectname copied " + + "to my-bucketname/my-objectname successfully"); + } + + { + // Create object "my-objectname" in bucket "my-bucketname" with SSE-C server-side encryption + // by copying from object "my-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .sse(ssec) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-objectname copied " + + "to my-bucketname/my-objectname successfully"); + } + + { + // Create object "my-objectname" in bucket "my-bucketname" by copying from SSE-C encrypted + // object "my-source-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .srcObject("my-source-objectname") + .srcSsec(ssec) // Replace with actual key. + .build()); + System.out.println( + "my-source-bucketname/my-source-objectname copied " + + "to my-bucketname/my-objectname successfully"); + } + + { + // Create object "my-objectname" in bucket "my-bucketname" with custom headers conditionally + // by copying from object "my-objectname" in bucket "my-source-bucketname". + minioClient.copyObject( + CopyObjectArgs.builder() + .bucket("my-bucketname") + .object("my-objectname") + .srcBucket("my-source-bucketname") + .headers(headers) // Replace with actual headers. + .srcMatchETag(etag) // Replace with actual ETag. + .build()); + System.out.println( + "my-source-bucketname/my-objectname copied " + + "to my-bucketname/my-objectname successfully"); + } } catch (MinioException e) { System.out.println("Error occurred: " + e); } diff --git a/examples/CopyObjectEncrypted.java b/examples/CopyObjectEncrypted.java deleted file mode 100644 index 9f1bd5b7e..000000000 --- a/examples/CopyObjectEncrypted.java +++ /dev/null @@ -1,92 +0,0 @@ -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.ServerSideEncryption; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import javax.crypto.spec.SecretKeySpec; - -public class CopyObjectEncrypted { - /** MinioClient.copyObject() example using SSE_C. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Generate a new 256 bit AES key - This key must be remembered by the client. - byte[] key = "01234567890123456789012345678901".getBytes("UTF-8"); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); - - ServerSideEncryption ssePut = ServerSideEncryption.withCustomerKey(secretKeySpec); - ServerSideEncryption sseSource = ServerSideEncryption.withCustomerKey(secretKeySpec); - - byte[] keyTarget = "98765432100123456789012345678901".getBytes("UTF-8"); - SecretKeySpec secretKeySpecTarget = new SecretKeySpec(keyTarget, "AES"); - - ServerSideEncryption sseTarget = ServerSideEncryption.withCustomerKey(secretKeySpecTarget); - - // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setSse(ssePut); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - System.out.println("my-objectname is uploaded successfully"); - - minioClient.copyObject( - "my-destbucketname", - "my-objectname-copy", - null, - sseTarget, - "my-bucketname", - "my-objectname", - sseSource, - null); - - bais.close(); - - System.out.println("my-objectname-copy copied to my-destbucketname successfully."); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - System.out.println("finished"); - } -} diff --git a/examples/CopyObjectEncryptedKms.java b/examples/CopyObjectEncryptedKms.java deleted file mode 100644 index 01f670149..000000000 --- a/examples/CopyObjectEncryptedKms.java +++ /dev/null @@ -1,85 +0,0 @@ -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.ServerSideEncryption; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; - -public class CopyObjectEncryptedKms { - /** MinioClient.copyObject() example using SSE_KMS. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - Map myContext = new HashMap<>(); - myContext.put("key1", "value1"); - - ServerSideEncryption sse = ServerSideEncryption.withManagedKeys("Key-Id", myContext); - - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setSse(sse); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - - minioClient.copyObject( - "my-destbucketname", - "my-objectname-copy", - null, - sse, - "my-bucketname", - "my-objectname", - null, - null); - System.out.println("my-objectname-copy copied to my-destbucketname successfully"); - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - System.out.println("finished"); - } -} diff --git a/examples/CopyObjectEncryptedS3.java b/examples/CopyObjectEncryptedS3.java deleted file mode 100644 index da9add9c6..000000000 --- a/examples/CopyObjectEncryptedS3.java +++ /dev/null @@ -1,80 +0,0 @@ -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.ServerSideEncryption; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -public class CopyObjectEncryptedS3 { - /** MinioClient.copyObject() example using SSE_S3. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - ServerSideEncryption sse = ServerSideEncryption.atRest(); - - // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setSse(sse); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - - minioClient.copyObject( - "my-destbucketname", - "my-objectname-copy", - null, - sse, - "my-bucketname", - "my-objectname", - null, - null); - System.out.println("my-objectname-copy copied to my-destbucketname successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - System.out.println("finished"); - } -} diff --git a/examples/CopyObjectMetadata.java b/examples/CopyObjectMetadata.java deleted file mode 100644 index 50f580746..000000000 --- a/examples/CopyObjectMetadata.java +++ /dev/null @@ -1,102 +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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import io.minio.CopyConditions; -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; - -public class CopyObjectMetadata { - /** MinioClient.copyObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. - minioClient.putObject( - "my-bucketname", "my-objectname", bais, new PutObjectOptions(bais.available(), -1)); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - - CopyConditions copyConditions = new CopyConditions(); - // Replace metadata on destination object with custom metadata. - copyConditions.setReplaceMetadataDirective(); - - Map metadata = new HashMap<>(); - metadata.put("Content-Type", "application/javascript"); - - minioClient.copyObject( - "my-destbucketname", - "my-objectname-copy", - metadata, - null, - "my-bucketname", - "my-objectname", - null, - copyConditions); - System.out.println("my-objectname-copy copied to my-destbucketname successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - } -} diff --git a/examples/PutGetObjectEncrypted.java b/examples/PutGetObjectEncrypted.java deleted file mode 100644 index a91ff053e..000000000 --- a/examples/PutGetObjectEncrypted.java +++ /dev/null @@ -1,99 +0,0 @@ -import io.minio.GetObjectArgs; -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.ServerSideEncryption; -import io.minio.ServerSideEncryptionCustomerKey; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import javax.crypto.KeyGenerator; - -public class PutGetObjectEncrypted { - /** MinioClient.putObject() and MinioClient.getObject() example for SSE_C. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 10; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Generate a new 256 bit AES key - This key must be remembered by the client. - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - - // To test SSE-C - ServerSideEncryptionCustomerKey ssec = - ServerSideEncryption.withCustomerKey(keyGen.generateKey()); - - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setSse(ssec); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - - bais.close(); - - System.out.println("my-objectname is encrypted and uploaded successfully."); - - InputStream stream = - minioClient.getObject( - GetObjectArgs.builder() - .bucket("my-bucketname") - .object("my-objectname") - .ssec(ssec) - .build()); - - // Read the input stream and print to the console till EOF. - byte[] buf = new byte[16384]; - int bytesRead; - while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) { - System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); - } - - // Close the input stream. - stream.close(); - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - } -} diff --git a/examples/PutObject.java b/examples/PutObject.java index 487ecd850..ca8dc8f57 100644 --- a/examples/PutObject.java +++ b/examples/PutObject.java @@ -15,12 +15,17 @@ */ import io.minio.MinioClient; -import io.minio.PutObjectOptions; +import io.minio.PutObjectArgs; +import io.minio.ServerSideEncryption; +import io.minio.ServerSideEncryptionCustomerKey; import io.minio.errors.MinioException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.KeyGenerator; public class PutObject { /** MinioClient.putObject() example. */ @@ -65,14 +70,104 @@ public static void main(String[] args) builder.append("---\n"); } - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); + { + // Create a InputStream for object upload. + ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); + + // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. + minioClient.putObject( + PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( + bais, bais.available(), -1) + .build()); + bais.close(); + System.out.println("my-objectname is uploaded successfully"); + } + + { + // Create a InputStream for object upload. + ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); + + // Generate a new 256 bit AES key - This key must be remembered by the client. + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + ServerSideEncryptionCustomerKey ssec = + ServerSideEncryption.withCustomerKey(keyGen.generateKey()); + + // Create encrypted object 'my-objectname' using SSE-C in 'my-bucketname' with content from + // the input stream. + minioClient.putObject( + PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( + bais, bais.available(), -1) + .sse(ssec) + .build()); + bais.close(); + System.out.println("my-objectname is uploaded successfully"); + } + + { + // Create a InputStream for object upload. + ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); + + Map myContext = new HashMap<>(); + myContext.put("key1", "value1"); + ServerSideEncryption sseKms = ServerSideEncryption.withManagedKeys("Key-Id", myContext); + + // Create encrypted object 'my-objectname' using SSE-KMS in 'my-bucketname' with content + // from the input stream. + minioClient.putObject( + PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( + bais, bais.available(), -1) + .sse(sseKms) + .build()); + bais.close(); + System.out.println("my-objectname is uploaded successfully"); + } + + { + // Create a InputStream for object upload. + ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); + + ServerSideEncryption sseS3 = ServerSideEncryption.atRest(); + + // Create encrypted object 'my-objectname' using SSE-S3 in 'my-bucketname' with content + // from the input stream. + minioClient.putObject( + PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( + bais, bais.available(), -1) + .sse(sseS3) + .build()); + bais.close(); + System.out.println("my-objectname is uploaded successfully"); + } + + { + // Create a InputStream for object upload. + ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); + + // Create headers + Map headers = new HashMap<>(); + // Add custom content type + headers.put("Content-Type", "application/octet-stream"); + // Add storage class + headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); + + // Add custom/user metadata + Map userMetadata = new HashMap<>(); + userMetadata.put("My-Project", "Project One"); + + // Create object 'my-objectname' with user metadata and other properties in 'my-bucketname' + // with content + // from the input stream. + minioClient.putObject( + PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( + bais, bais.available(), -1) + .headers(headers) + .userMetadata(userMetadata) + .build()); + bais.close(); + System.out.println("my-objectname is uploaded successfully"); + } - // Create object 'my-objectname' in 'my-bucketname' with content from the input stream. - minioClient.putObject( - "my-bucketname", "my-objectname", bais, new PutObjectOptions(bais.available(), -1)); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); } catch (MinioException e) { System.out.println("Error occurred: " + e); } diff --git a/examples/PutObjectEncryptedKms.java b/examples/PutObjectEncryptedKms.java deleted file mode 100644 index f90b49b6c..000000000 --- a/examples/PutObjectEncryptedKms.java +++ /dev/null @@ -1,75 +0,0 @@ -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.ServerSideEncryption; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; - -public class PutObjectEncryptedKms { - /** MinioClient.getObject() example. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 10; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - Map myContext = new HashMap<>(); - myContext.put("key1", "value1"); - // To test SSE-KMS - ServerSideEncryption sse = ServerSideEncryption.withManagedKeys("Key-Id", myContext); - - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setSse(sse); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - - bais.close(); - - System.out.println("my-objectname is encrypted and uploaded successfully."); - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - } -} diff --git a/examples/PutObjectEncryptedS3.java b/examples/PutObjectEncryptedS3.java deleted file mode 100644 index 2ac37fba7..000000000 --- a/examples/PutObjectEncryptedS3.java +++ /dev/null @@ -1,71 +0,0 @@ -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.ServerSideEncryption; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -public class PutObjectEncryptedS3 { - /** MinioClient.putObject() example. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 10; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // To test SSE-S3 - ServerSideEncryption sse = ServerSideEncryption.atRest(); - - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setSse(sse); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - - bais.close(); - - System.out.println("my-objectname is encrypted and uploaded successfully."); - - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - } -} diff --git a/examples/PutObjectProgressBar.java b/examples/PutObjectProgressBar.java index d68bbd33f..a224afd0a 100644 --- a/examples/PutObjectProgressBar.java +++ b/examples/PutObjectProgressBar.java @@ -15,7 +15,7 @@ */ import io.minio.MinioClient; -import io.minio.PutObjectOptions; +import io.minio.PutObjectArgs; import io.minio.errors.MinioException; import java.io.BufferedInputStream; import java.io.File; @@ -48,7 +48,10 @@ public static void main(String[] args) InputStream pis = new BufferedInputStream( new ProgressStream("Uploading... ", ProgressBarStyle.ASCII, new FileInputStream(file))); - minioClient.putObject(bucketName, objectName, pis, new PutObjectOptions(pis.available(), -1)); + minioClient.putObject( + PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( + pis, pis.available(), -1) + .build()); pis.close(); System.out.println("my-objectname is uploaded successfully"); } diff --git a/examples/PutObjectUiProgressBar.java b/examples/PutObjectUiProgressBar.java index 346659b6d..0bf15582e 100644 --- a/examples/PutObjectUiProgressBar.java +++ b/examples/PutObjectUiProgressBar.java @@ -15,7 +15,7 @@ */ import io.minio.MinioClient; -import io.minio.PutObjectOptions; +import io.minio.PutObjectArgs; import io.minio.errors.MinioException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -80,7 +80,9 @@ private void uploadFile(String fileName) pmis.getProgressMonitor().setMillisToPopup(10); minioClient.putObject( - "bank", "my-objectname", pmis, new PutObjectOptions(pmis.available(), -1)); + PutObjectArgs.builder().bucket("bank").object("my-objectname").stream( + pmis, pmis.available(), -1) + .build()); System.out.println("my-objectname is uploaded successfully"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block diff --git a/examples/PutObjectWithMetadata.java b/examples/PutObjectWithMetadata.java deleted file mode 100644 index f5dfa0147..000000000 --- a/examples/PutObjectWithMetadata.java +++ /dev/null @@ -1,95 +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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import io.minio.MinioClient; -import io.minio.PutObjectOptions; -import io.minio.errors.MinioException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; - -public class PutObjectWithMetadata { - /** MinioClient.putObject() example. */ - public static void main(String[] args) - throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - /* play.min.io for test and development. */ - MinioClient minioClient = - new MinioClient( - "https://play.min.io", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"); - - /* Amazon S3: */ - // MinioClient minioClient = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", - // "YOUR-SECRETACCESSKEY"); - - // Create some content for the object. - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < 1000; i++) { - builder.append( - "Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. "); - builder.append("(29 letters)\n"); - builder.append( - "Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. "); - builder.append("(31 letters)\n"); - builder.append( - "Pack my box with five dozen liquor jugs: According to Wikipedia, this one is used on "); - builder.append("NASAs Space Shuttle. (32 letters)\n"); - builder.append( - "The quick onyx goblin jumps over the lazy dwarf: Flavor text from an Unhinged Magic Card. "); - builder.append("(39 letters)\n"); - builder.append( - "How razorback-jumping frogs can level six piqued gymnasts!: Not going to win any brevity "); - builder.append("awards at 49 letters long, but old-time Mac users may recognize it.\n"); - builder.append( - "Cozy lummox gives smart squid who asks for job pen: A 41-letter tester sentence for Mac "); - builder.append("computers after System 7.\n"); - builder.append( - "A few others we like: Amazingly few discotheques provide jukeboxes; Now fax quiz Jack! my "); - builder.append("brave ghost pled; Watch Jeopardy!, Alex Trebeks fun TV quiz game.\n"); - builder.append("---\n"); - } - - // Create a InputStream for object upload. - ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8")); - - // Create metadata map - Map headerMap = new HashMap<>(); - - // Add custom metadata - headerMap.put("CustomMeta", "TEST"); - - // Add custom content type - headerMap.put("Content-Type", "application/octet-stream"); - - // Add storage class - headerMap.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); - - // Create object 'my-objectname' in 'my-bucketname' with custom metadata in headerMap - PutObjectOptions options = new PutObjectOptions(bais.available(), -1); - options.setHeaders(headerMap); - minioClient.putObject("my-bucketname", "my-objectname", bais, options); - bais.close(); - System.out.println("my-objectname is uploaded successfully"); - } catch (MinioException e) { - System.out.println("Error occurred: " + e); - } - } -} diff --git a/examples/SelectObjectContent.java b/examples/SelectObjectContent.java index 145d9ddc5..5ed8b9252 100644 --- a/examples/SelectObjectContent.java +++ b/examples/SelectObjectContent.java @@ -15,7 +15,7 @@ */ import io.minio.MinioClient; -import io.minio.PutObjectOptions; +import io.minio.PutObjectArgs; import io.minio.SelectObjectContentArgs; import io.minio.SelectResponseStream; import io.minio.errors.MinioException; @@ -56,7 +56,9 @@ public static void main(String[] args) .getBytes(StandardCharsets.UTF_8); ByteArrayInputStream bais = new ByteArrayInputStream(data); minioClient.putObject( - "my-bucketname", "my-objectname", bais, new PutObjectOptions(data.length, -1)); + PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( + bais, data.length, -1) + .build()); String sqlExpression = "select * from S3Object"; InputSerialization is = diff --git a/functional/FunctionalTest.java b/functional/FunctionalTest.java index b603076f2..28719838f 100644 --- a/functional/FunctionalTest.java +++ b/functional/FunctionalTest.java @@ -22,7 +22,7 @@ import io.minio.BucketExistsArgs; import io.minio.CloseableIterator; import io.minio.ComposeSource; -import io.minio.CopyConditions; +import io.minio.CopyObjectArgs; import io.minio.DeleteBucketEncryptionArgs; import io.minio.DeleteBucketLifeCycleArgs; import io.minio.DeleteBucketNotificationArgs; @@ -30,6 +30,7 @@ import io.minio.DeleteBucketTagsArgs; import io.minio.DeleteDefaultRetentionArgs; import io.minio.DeleteObjectTagsArgs; +import io.minio.Directive; import io.minio.DisableObjectLegalHoldArgs; import io.minio.DisableVersioningArgs; import io.minio.DownloadObjectArgs; @@ -2469,88 +2470,92 @@ public static void threadedPutObject() throws Exception { } } - /** Test: copyObject(String bucketName, String objectName, String destBucketName). */ - public static void copyObject_test1() throws Exception { - String methodName = "copyObject(String bucketName, String objectName, String destBucketName)"; + public static void testCopyObject( + String methodName, ServerSideEncryption sse, CopyObjectArgs args, boolean negativeCase) + throws Exception { if (!mintEnv) { System.out.println("Test: " + methodName); } + String srcObject = args.object(); + if (args.srcObject() != null) { + srcObject = args.srcObject(); + } + long startTime = System.currentTimeMillis(); try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - client.copyObject(destBucketName, objectName, null, null, bucketName, null, null, null); - client - .getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build()) - .close(); + client.makeBucket(MakeBucketArgs.builder().bucket(args.srcBucket()).build()); + try { + PutObjectOptions options = new PutObjectOptions(1 * KB, -1); + if (sse != null) { + options.setSse(sse); + } + client.putObject(args.srcBucket(), srcObject, new ContentInputStream(1 * KB), options); + + if (negativeCase) { + try { + client.copyObject(args); + } catch (ErrorResponseException e) { + if (e.errorResponse().errorCode() != ErrorCode.PRECONDITION_FAILED) { + throw e; + } + } + } else { + client.copyObject(args); - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(destBucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - mintSuccessLog(methodName, null, startTime); + ServerSideEncryptionCustomerKey ssec = null; + if (sse instanceof ServerSideEncryptionCustomerKey) { + ssec = (ServerSideEncryptionCustomerKey) sse; + } + client.statObject( + StatObjectArgs.builder() + .bucket(args.bucket()) + .object(args.object()) + .ssec(ssec) + .build()); + } + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(args.srcBucket()).object(srcObject).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(args.bucket()).object(args.object()).build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(args.srcBucket()).build()); + } } catch (Exception e) { handleException(methodName, null, startTime, e); } } + /** Test: copyObject(CopyObjectArgs args). */ + public static void copyObject_test1() throws Exception { + testCopyObject( + "copyObject(CopyObjectArgs args)", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .srcBucket(getRandomName()) + .build(), + false); + } + /** * Test: copyObject(String bucketName, String objectName, String destBucketName, CopyConditions * copyConditions) with ETag to match. */ public static void copyObject_test2() throws Exception { - if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions) with Matching ETag (Negative Case)"); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - CopyConditions invalidETag = new CopyConditions(); - invalidETag.setMatchETag("TestETag"); - - try { - client.copyObject( - destBucketName, objectName, null, null, bucketName, null, null, invalidETag); - } catch (ErrorResponseException e) { - if (e.errorResponse().errorCode() != ErrorCode.PRECONDITION_FAILED) { - throw e; - } - } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - - mintSuccessLog( - "copyObject(String bucketName, String objectName, String destBucketName," - + " CopyConditions copyConditions)", - "CopyConditions: invalidETag", - startTime); - } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions)", - "CopyConditions: invalidETag", - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; - } + testCopyObject( + "copyObject(CopyObjectArgs args)", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .srcMatchETag("invalid-etag") + .build(), + true); } /** @@ -2558,40 +2563,43 @@ public static void copyObject_test2() throws Exception { * copyConditions) with ETag to match. */ public static void copyObject_test3() throws Exception { - String methodName = - "copyObject(String bucketName, String objectName, String destBucketName," - + " CopyConditions copyConditions) with Matching ETag (Positive Case)"; + String methodName = "copyObject(CopyObjectArgs args)"; if (!mintEnv) { System.out.println("Test: " + methodName); } long startTime = System.currentTimeMillis(); + String srcBucketName = getRandomName(); + String srcObjectName = getRandomName(); try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); + client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); + try { + client.putObject( + srcBucketName, + srcObjectName, + new ContentInputStream(1 * KB), + new PutObjectOptions(1 * KB, -1)); + ObjectStat stat = + client.statObject( + StatObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.copyObject( + CopyObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .srcBucket(srcBucketName) + .srcObject(srcObjectName) + .srcMatchETag(stat.etag()) + .build()); + client.statObject( + StatObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - ObjectStat stat = - client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setMatchETag(stat.etag()); - - // File should be copied as ETag set in copyConditions matches object's ETag. - client.copyObject( - destBucketName, objectName, null, null, bucketName, null, null, copyConditions); - client - .getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build()) - .close(); - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(destBucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - mintSuccessLog(methodName, null, startTime); } catch (Exception e) { handleException(methodName, null, startTime, e); } @@ -2602,102 +2610,17 @@ public static void copyObject_test3() throws Exception { * copyConditions) with ETag to not match. */ public static void copyObject_test4() throws Exception { - String methodName = - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions) with not matching ETag" - + " (Positive Case)"; - if (!mintEnv) { - System.out.println("Test: " + methodName); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setMatchETagNone("TestETag"); - - // File should be copied as ETag set in copyConditions doesn't match object's - // ETag. - client.copyObject( - destBucketName, objectName, null, null, bucketName, null, null, copyConditions); - client - .getObject(GetObjectArgs.builder().bucket(destBucketName).object(objectName).build()) - .close(); - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(destBucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - handleException(methodName, null, startTime, e); - } - } - - /** - * Test: copyObject(String bucketName, String objectName, String destBucketName, CopyConditions - * copyConditions) with ETag to not match. - */ - public static void copyObject_test5() throws Exception { - if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions) with not matching ETag" - + " (Negative Case)"); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - ObjectStat stat = - client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); - CopyConditions matchingETagNone = new CopyConditions(); - matchingETagNone.setMatchETagNone(stat.etag()); - - try { - client.copyObject( - destBucketName, objectName, null, null, bucketName, null, null, matchingETagNone); - } catch (ErrorResponseException e) { - // File should not be copied as ETag set in copyConditions matches object's - // ETag. - if (e.errorResponse().errorCode() != ErrorCode.PRECONDITION_FAILED) { - throw e; - } - } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - - mintSuccessLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions)", - null, - startTime); - } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions)", - null, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; - } + testCopyObject( + "copyObject(CopyObjectArgs args)", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .srcNotMatchETag("not-etag-of-source-object") + .build(), + false); } /** @@ -2705,43 +2628,17 @@ public static void copyObject_test5() throws Exception { * copyConditions) with object modified after condition. */ public static void copyObject_test6() throws Exception { - String methodName = - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions) with modified after " - + "condition (Positive Case)"; - String args = "CopyCondition: modifiedDateCondition"; - if (!mintEnv) { - System.out.println("Test: " + methodName); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - CopyConditions modifiedDateCondition = new CopyConditions(); - modifiedDateCondition.setModified(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)); - - // File should be copied as object was modified after the set date. - client.copyObject( - destBucketName, objectName, null, null, bucketName, null, null, modifiedDateCondition); - client - .getObject(GetObjectArgs.builder().bucket(destBucketName).object(objectName).build()) - .close(); - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(destBucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - mintSuccessLog(methodName, args, startTime); - } catch (Exception e) { - handleException(methodName, args, startTime, e); - } + testCopyObject( + "copyObject(CopyObjectArgs args)", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .srcModifiedSince(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)) + .build(), + false); } /** @@ -2749,64 +2646,17 @@ public static void copyObject_test6() throws Exception { * copyConditions) with object modified after condition. */ public static void copyObject_test7() throws Exception { - if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions) with modified after" - + " condition (Negative Case)"); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - CopyConditions invalidUnmodifiedCondition = new CopyConditions(); - invalidUnmodifiedCondition.setUnmodified( - ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)); - - try { - client.copyObject( - destBucketName, - objectName, - null, - null, - bucketName, - null, - null, - invalidUnmodifiedCondition); - } catch (ErrorResponseException e) { - // File should not be copied as object was modified after date set in - // copyConditions. - if (e.errorResponse().errorCode() != ErrorCode.PRECONDITION_FAILED) { - throw e; - } - } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - // Destination bucket is expected to be empty, otherwise it will trigger an - // exception. - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - mintSuccessLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions)", - "CopyCondition: invalidUnmodifiedCondition", - startTime); - } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions)", - "CopyCondition: invalidUnmodifiedCondition", - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; - } + testCopyObject( + "copyObject(CopyObjectArgs args)", + null, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .srcUnmodifiedSince(ZonedDateTime.of(2015, 05, 3, 3, 10, 10, 0, Time.UTC)) + .build(), + true); } /** @@ -2814,61 +2664,59 @@ public static void copyObject_test7() throws Exception { * copyConditions, Map metadata) replace object metadata. */ public static void copyObject_test8() throws Exception { + String methodName = "copyObject(CopyObjectArgs args)"; if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions, Map metadata)" - + " replace object metadata"); + System.out.println("Test: " + methodName); } long startTime = System.currentTimeMillis(); + String srcBucketName = getRandomName(); + String srcObjectName = getRandomName(); try { - String objectName = getRandomName(); - try (final InputStream is = new ContentInputStream(1 * KB)) { - client.putObject(bucketName, objectName, is, new PutObjectOptions(1 * KB, -1)); - } - - String destBucketName = getRandomName(); - client.makeBucket(MakeBucketArgs.builder().bucket(destBucketName).build()); - - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setReplaceMetadataDirective(); - - Map metadata = new HashMap<>(); - metadata.put("Content-Type", customContentType); + client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); + try { + client.putObject( + srcBucketName, + srcObjectName, + new ContentInputStream(1 * KB), + new PutObjectOptions(1 * KB, -1)); - client.copyObject( - destBucketName, objectName, metadata, null, bucketName, objectName, null, copyConditions); + Map headers = new HashMap<>(); + headers.put("Content-Type", customContentType); + headers.put("X-Amz-Meta-My-Project", "Project One"); - ObjectStat objectStat = - client.statObject( - StatObjectArgs.builder().bucket(destBucketName).object(objectName).build()); - if (!customContentType.equals(objectStat.contentType())) { - throw new Exception( - "content type differs. expected: " - + customContentType - + ", got: " - + objectStat.contentType()); + client.copyObject( + CopyObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .srcBucket(srcBucketName) + .srcObject(srcObjectName) + .headers(headers) + .metadataDirective(Directive.REPLACE) + .build()); + ObjectStat stat = + client.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .build()); + if (!customContentType.equals(stat.contentType())) { + throw new Exception( + "content type differs. expected: " + + customContentType + + ", got: " + + stat.contentType()); + } + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - client.removeObject( - RemoveObjectArgs.builder().bucket(destBucketName).object(objectName).build()); - client.removeBucket(RemoveBucketArgs.builder().bucket(destBucketName).build()); - mintSuccessLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions, Map metadata)", - null, - startTime); } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions, Map metadata)", - null, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; + handleException(methodName, null, startTime, e); } } @@ -2877,59 +2725,53 @@ public static void copyObject_test8() throws Exception { * copyConditions, Map metadata) remove object metadata. */ public static void copyObject_test9() throws Exception { + String methodName = "copyObject(CopyObjectArgs args)"; if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, String destBucketName," - + "CopyConditions copyConditions, Map metadata)" - + " remove object metadata"); + System.out.println("Test: " + methodName); } long startTime = System.currentTimeMillis(); + String srcBucketName = getRandomName(); + String srcObjectName = getRandomName(); try { - String objectName = getRandomName(); - Map headerMap = new HashMap<>(); - headerMap.put("Test", "testValue"); - - try (final InputStream is = new ContentInputStream(1)) { - PutObjectOptions options = new PutObjectOptions(1, -1); - options.setHeaders(headerMap); - client.putObject(bucketName, objectName, is, options); - } + client.makeBucket(MakeBucketArgs.builder().bucket(srcBucketName).build()); + try { + Map headers = new HashMap<>(); + headers.put("Content-Type", customContentType); + headers.put("X-Amz-Meta-My-Project", "Project One"); + PutObjectOptions options = new PutObjectOptions(1 * KB, -1); + options.setHeaders(headers); - // Attempt to remove the user-defined metadata from the object - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setReplaceMetadataDirective(); + client.putObject(srcBucketName, srcObjectName, new ContentInputStream(1 * KB), options); - client.copyObject( - bucketName, - objectName, - new HashMap(), - null, - bucketName, - objectName, - null, - copyConditions); - ObjectStat objectStat = - client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); - if (objectStat.httpHeaders().containsKey("X-Amz-Meta-Test")) { - throw new Exception("expected user-defined metadata has been removed"); + client.copyObject( + CopyObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .srcBucket(srcBucketName) + .srcObject(srcObjectName) + .metadataDirective(Directive.REPLACE) + .build()); + ObjectStat stat = + client.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(srcObjectName + "-copy") + .build()); + + if (stat.httpHeaders().containsKey("X-Amz-Meta-My-Project")) { + throw new Exception("expected user metadata to be removed in new object"); + } + mintSuccessLog(methodName, null, startTime); + } finally { + client.removeObject( + RemoveObjectArgs.builder().bucket(srcBucketName).object(srcObjectName).build()); + client.removeObject( + RemoveObjectArgs.builder().bucket(bucketName).object(srcObjectName + "-copy").build()); + client.removeBucket(RemoveBucketArgs.builder().bucket(srcBucketName).build()); } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - mintSuccessLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions, Map metadata)", - null, - startTime); } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, String destBucketName, " - + "CopyConditions copyConditions, Map metadata)", - null, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; + handleException(methodName, null, startTime, e); } } @@ -2939,75 +2781,22 @@ public static void copyObject_test9() throws Exception { * SSE_C. */ public static void copyObject_test10() throws Exception { - if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)" - + " using SSE_C. "); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - - // Generate a new 256 bit AES key - This key must be remembered by the client. - byte[] key = "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); - - ServerSideEncryption ssePut = ServerSideEncryption.withCustomerKey(secretKeySpec); - ServerSideEncryption sseSource = ServerSideEncryption.withCustomerKey(secretKeySpec); - - byte[] keyTarget = "98765432100123456789012345678901".getBytes(StandardCharsets.UTF_8); - SecretKeySpec secretKeySpecTarget = new SecretKeySpec(keyTarget, "AES"); - - ServerSideEncryptionCustomerKey sseTarget = - ServerSideEncryption.withCustomerKey(secretKeySpecTarget); - - try (final InputStream is = new ContentInputStream(1)) { - PutObjectOptions options = new PutObjectOptions(1, -1); - options.setSse(ssePut); - client.putObject(bucketName, objectName, is, options); - } - - // Attempt to remove the user-defined metadata from the object - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setReplaceMetadataDirective(); - - client.copyObject( - bucketName, - objectName, - null, - sseTarget, - bucketName, - objectName, - sseSource, - copyConditions); - - client.statObject( - StatObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .ssec(sseTarget) - .build()); // Check for object existence. - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - mintSuccessLog( - "copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)" - + " using SSE_C.", - null, - startTime); - } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)" - + " using SSE_C.", - null, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; - } + ServerSideEncryptionCustomerKey ssec = + ServerSideEncryption.withCustomerKey( + new SecretKeySpec( + "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8), "AES")); + testCopyObject( + "copyObject(CopyObjectArgs args)", + ssec, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(ssec) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .srcSsec(ssec) + .build(), + false); } /** @@ -3016,55 +2805,18 @@ public static void copyObject_test10() throws Exception { * SSE_S3. */ public static void copyObject_test11() throws Exception { - if (!mintEnv) { - System.out.println( - "Test: copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)" - + " using SSE_S3. "); - } - - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - - ServerSideEncryption sse = ServerSideEncryption.atRest(); - - try (final InputStream is = new ContentInputStream(1)) { - PutObjectOptions options = new PutObjectOptions(1, -1); - options.setSse(sse); - client.putObject(bucketName, objectName, is, options); - } - - // Attempt to remove the user-defined metadata from the object - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setReplaceMetadataDirective(); - - client.copyObject( - bucketName, objectName, null, sse, bucketName, objectName, null, copyConditions); - ObjectStat objectStat = - client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); - if (objectStat.httpHeaders().containsKey("X-Amz-Meta-Test")) { - throw new Exception("expected user-defined metadata has been removed"); - } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - mintSuccessLog( - "copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)" - + " using SSE_S3.", - null, - startTime); - } catch (Exception e) { - mintFailedLog( - "copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)" - + " using SSE_S3.", - null, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; - } + ServerSideEncryption sseS3 = ServerSideEncryption.atRest(); + testCopyObject( + "copyObject(CopyObjectArgs args)", + sseS3, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(sseS3) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .build(), + false); } /** @@ -3073,56 +2825,26 @@ public static void copyObject_test11() throws Exception { * SSE_KMS. */ public static void copyObject_test12() throws Exception { - String methodName = - "SSE-KMS: copyObject(String bucketName, String objectName, ServerSideEncryption sseSource, " - + "String destBucketName, CopyConditions copyConditions, ServerSideEncryption sseTarget)"; - if (!mintEnv) { - System.out.println("Test: " + methodName); + String keyId = System.getenv("MINT_KEY_ID"); + if (keyId == null || keyId.isEmpty()) { + mintIgnoredLog("copyObject(CopyObjectArgs args)", null, System.currentTimeMillis()); + return; } - long startTime = System.currentTimeMillis(); - try { - String objectName = getRandomName(); - - Map myContext = new HashMap<>(); - myContext.put("key1", "value1"); - - String keyId = ""; - keyId = System.getenv("MINT_KEY_ID"); - if (keyId.equals("")) { - mintIgnoredLog(methodName, null, startTime); - } - ServerSideEncryption sse = ServerSideEncryption.withManagedKeys("keyId", myContext); - - try (final InputStream is = new ContentInputStream(1)) { - PutObjectOptions options = new PutObjectOptions(1, -1); - options.setSse(sse); - client.putObject(bucketName, objectName, is, options); - } - - // Attempt to remove the user-defined metadata from the object - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setReplaceMetadataDirective(); - - client.copyObject( - bucketName, objectName, null, sse, bucketName, objectName, null, copyConditions); - ObjectStat objectStat = - client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); - if (objectStat.httpHeaders().containsKey("X-Amz-Meta-Test")) { - throw new Exception("expected user-defined metadata has been removed"); - } - - client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); - mintSuccessLog(methodName, null, startTime); - } catch (Exception e) { - mintFailedLog( - methodName, - null, - startTime, - null, - e.toString() + " >>> " + Arrays.toString(e.getStackTrace())); - throw e; - } + Map myContext = new HashMap<>(); + myContext.put("key1", "value1"); + ServerSideEncryption sseKms = ServerSideEncryption.withManagedKeys(keyId, myContext); + testCopyObject( + "copyObject(CopyObjectArgs args)", + sseKms, + CopyObjectArgs.builder() + .bucket(bucketName) + .object(getRandomName()) + .sse(sseKms) + .srcBucket(getRandomName()) + .srcObject(getRandomName()) + .build(), + false); } /** @@ -4687,7 +4409,6 @@ public static void runTests() throws Exception { copyObject_test2(); copyObject_test3(); copyObject_test4(); - copyObject_test5(); copyObject_test6(); copyObject_test7(); copyObject_test8();