1 /* 2 * Copyright 2020 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.bremersee.data.minio; 18 19 import io.minio.BucketExistsArgs; 20 import io.minio.CloseableIterator; 21 import io.minio.ComposeObjectArgs; 22 import io.minio.CopyObjectArgs; 23 import io.minio.DeleteBucketEncryptionArgs; 24 import io.minio.DeleteBucketLifecycleArgs; 25 import io.minio.DeleteBucketNotificationArgs; 26 import io.minio.DeleteBucketPolicyArgs; 27 import io.minio.DeleteBucketReplicationArgs; 28 import io.minio.DeleteBucketTagsArgs; 29 import io.minio.DeleteObjectLockConfigurationArgs; 30 import io.minio.DeleteObjectTagsArgs; 31 import io.minio.DisableObjectLegalHoldArgs; 32 import io.minio.DownloadObjectArgs; 33 import io.minio.EnableObjectLegalHoldArgs; 34 import io.minio.GetBucketEncryptionArgs; 35 import io.minio.GetBucketLifecycleArgs; 36 import io.minio.GetBucketNotificationArgs; 37 import io.minio.GetBucketPolicyArgs; 38 import io.minio.GetBucketReplicationArgs; 39 import io.minio.GetBucketTagsArgs; 40 import io.minio.GetBucketVersioningArgs; 41 import io.minio.GetObjectArgs; 42 import io.minio.GetObjectLockConfigurationArgs; 43 import io.minio.GetObjectRetentionArgs; 44 import io.minio.GetObjectTagsArgs; 45 import io.minio.GetPresignedObjectUrlArgs; 46 import io.minio.IsObjectLegalHoldEnabledArgs; 47 import io.minio.ListBucketsArgs; 48 import io.minio.ListObjectsArgs; 49 import io.minio.ListenBucketNotificationArgs; 50 import io.minio.MakeBucketArgs; 51 import io.minio.MinioClient; 52 import io.minio.ObjectWriteResponse; 53 import io.minio.PostPolicy; 54 import io.minio.PutObjectArgs; 55 import io.minio.RemoveBucketArgs; 56 import io.minio.RemoveObjectArgs; 57 import io.minio.RemoveObjectsArgs; 58 import io.minio.Result; 59 import io.minio.SelectObjectContentArgs; 60 import io.minio.SelectResponseStream; 61 import io.minio.SetBucketEncryptionArgs; 62 import io.minio.SetBucketLifecycleArgs; 63 import io.minio.SetBucketNotificationArgs; 64 import io.minio.SetBucketPolicyArgs; 65 import io.minio.SetBucketReplicationArgs; 66 import io.minio.SetBucketTagsArgs; 67 import io.minio.SetBucketVersioningArgs; 68 import io.minio.SetObjectLockConfigurationArgs; 69 import io.minio.SetObjectRetentionArgs; 70 import io.minio.SetObjectTagsArgs; 71 import io.minio.StatObjectArgs; 72 import io.minio.StatObjectResponse; 73 import io.minio.UploadObjectArgs; 74 import io.minio.messages.Bucket; 75 import io.minio.messages.DeleteError; 76 import io.minio.messages.Item; 77 import io.minio.messages.LifecycleConfiguration; 78 import io.minio.messages.NotificationConfiguration; 79 import io.minio.messages.NotificationRecords; 80 import io.minio.messages.ObjectLockConfiguration; 81 import io.minio.messages.ReplicationConfiguration; 82 import io.minio.messages.Retention; 83 import io.minio.messages.SseConfiguration; 84 import io.minio.messages.Tags; 85 import io.minio.messages.VersioningConfiguration; 86 import java.io.InputStream; 87 import java.nio.file.Files; 88 import java.nio.file.Path; 89 import java.nio.file.Paths; 90 import java.util.List; 91 import java.util.Map; 92 import java.util.Optional; 93 import org.springframework.validation.annotation.Validated; 94 95 /** 96 * The minio operations. 97 * 98 * @author Christian Bremer 99 */ 100 @Validated 101 public interface MinioOperations { 102 103 // DO NOT USE GENERATE JAVA DOCS! 104 105 /** 106 * Execute minio callback. 107 * 108 * @param <T> the type of the result 109 * @param callback the callback 110 * @return the result 111 */ 112 <T> T execute(MinioClientCallback<T> callback); 113 114 // Bucket operations 115 116 /** 117 * Lists bucket information of all buckets. 118 * 119 * <pre>Example: {@code 120 * List<Bucket> bucketList = minioOperations.listBuckets(); 121 * for (Bucket bucket : bucketList) { 122 * System.out.println(bucket.creationDate() + ", " + bucket.name()); 123 * } 124 * } 125 * </pre> 126 * 127 * @return list of bucket information 128 */ 129 default List<Bucket> listBuckets() { 130 return execute(MinioClient::listBuckets); 131 } 132 133 /** 134 * Lists bucket information of all buckets. 135 * 136 * <pre>Example: {@code 137 * List<Bucket> bucketList = 138 * minioClient.listBuckets(ListBucketsArgs.builder().extraHeaders(headers).build()); 139 * for (Bucket bucket : bucketList) { 140 * System.out.println(bucket.creationDate() + ", " + bucket.name()); 141 * } 142 * }* 143 * </pre> 144 * 145 * @param args the list buckets arguments 146 * @return list of bucket information 147 */ 148 default List<Bucket> listBuckets(ListBucketsArgs args) { 149 return execute(minioClient -> minioClient.listBuckets(args)); 150 } 151 152 /** 153 * Checks if a bucket exists. 154 * 155 * <pre>Example: {@code 156 * boolean found = 157 * minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-bucketname").build()); 158 * if (found) { 159 * System.out.println("my-bucketname exists"); 160 * } else { 161 * System.out.println("my-bucketname does not exist"); 162 * } 163 * }* 164 * </pre> 165 * 166 * @param args the bucket exists arguments 167 * @return true if the bucket exists 168 */ 169 default boolean bucketExists(BucketExistsArgs args) { 170 return execute(minioClient -> minioClient.bucketExists(args)); 171 } 172 173 /** 174 * Creates a bucket with region and object lock. 175 * 176 * <pre>Example: {@code 177 * // Create bucket with default region. 178 * minioClient.makeBucket( 179 * MakeBucketArgs.builder() 180 * .bucket("my-bucketname") 181 * .build()); 182 * 183 * // Create bucket with specific region. 184 * minioClient.makeBucket( 185 * MakeBucketArgs.builder() 186 * .bucket("my-bucketname") 187 * .region("us-west-1") 188 * .build()); 189 * 190 * // Create object-lock enabled bucket with specific region. 191 * minioClient.makeBucket( 192 * MakeBucketArgs.builder() 193 * .bucket("my-bucketname") 194 * .region("us-west-1") 195 * .objectLock(true) 196 * .build()); 197 * }* 198 * </pre> 199 * 200 * @param args object with bucket name, region and lock functionality 201 */ 202 default void makeBucket(MakeBucketArgs args) { 203 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 204 .makeBucket(args)); 205 } 206 207 /** 208 * Removes an empty bucket using arguments. 209 * 210 * <pre>Example: {@code 211 * minioClient.removeBucket(RemoveBucketArgs.builder().bucket("my-bucketname").build()); 212 * }* 213 * </pre> 214 * 215 * @param args the remove bucket arguments 216 */ 217 default void removeBucket(RemoveBucketArgs args) { 218 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 219 .removeBucket(args)); 220 } 221 222 /** 223 * Gets encryption configuration of a bucket. 224 * 225 * <pre>Example: {@code 226 * SseConfiguration config = 227 * minioClient.getBucketEncryption( 228 * GetBucketEncryptionArgs.builder().bucket("my-bucketname").build()); 229 * }* 230 * </pre> 231 * 232 * @param args get bucket encryption arguments 233 * @return server -side encryption configuration 234 */ 235 default SseConfiguration getBucketEncryption(GetBucketEncryptionArgs args) { 236 return execute(minioClient -> minioClient.getBucketEncryption(args)); 237 } 238 239 /** 240 * Sets encryption configuration of a bucket. 241 * 242 * <pre>Example: {@code 243 * minioClient.setBucketEncryption( 244 * SetBucketEncryptionArgs.builder().bucket("my-bucketname").config(config).build()); 245 * }* 246 * </pre> 247 * 248 * @param args bucket encryption arguments 249 */ 250 default void setBucketEncryption(SetBucketEncryptionArgs args) { 251 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 252 .setBucketEncryption(args)); 253 } 254 255 /** 256 * Deletes encryption configuration of a bucket. 257 * 258 * <pre>Example: {@code 259 * minioClient.deleteBucketEncryption( 260 * DeleteBucketEncryptionArgs.builder().bucket("my-bucketname").build()); 261 * }* 262 * </pre> 263 * 264 * @param args delete bucket encryption arguments 265 */ 266 default void deleteBucketEncryption(DeleteBucketEncryptionArgs args) { 267 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 268 .deleteBucketEncryption(args)); 269 } 270 271 /** 272 * Gets lifecycle configuration of a bucket. 273 * 274 * <pre>Example: {@code 275 * LifecycleConfiguration config = 276 * minioClient.getBucketLifecycle( 277 * GetBucketLifecycleArgs.builder().bucket("my-bucketname").build()); 278 * }* 279 * </pre> 280 * 281 * @param args get bucket lifecycle arguments 282 * @return the lifecycle configuration 283 */ 284 default Optional<LifecycleConfiguration> getBucketLifecycle(GetBucketLifecycleArgs args) { 285 return execute(minioClient -> Optional.ofNullable(minioClient.getBucketLifecycle(args))); 286 } 287 288 /** 289 * Sets lifecycle configuration to a bucket. 290 * 291 * <pre>Example: {@code 292 * List<LifecycleRule> rules = new LinkedList<>(); 293 * rules.add( 294 * new LifecycleRule( 295 * Status.ENABLED, 296 * null, 297 * new Expiration((ZonedDateTime) null, 365, null), 298 * new RuleFilter("logs/"), 299 * "rule2", 300 * null, 301 * null, 302 * null)); 303 * LifecycleConfiguration config = new LifecycleConfiguration(rules); 304 * minioClient.setBucketLifecycle( 305 * SetBucketLifecycleArgs.builder().bucket("my-bucketname").config(config).build()); 306 * }* 307 * </pre> 308 * 309 * @param args set bucket lifecycle arguments 310 */ 311 default void setBucketLifecycle(SetBucketLifecycleArgs args) { 312 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 313 .setBucketLifecycle(args)); 314 } 315 316 /** 317 * Deletes lifecycle configuration of a bucket. 318 * 319 * <pre>Example: {@code 320 * deleteBucketLifecycle(DeleteBucketLifecycleArgs.builder().bucket("my-bucketname").build()); 321 * }* 322 * </pre> 323 * 324 * @param args {@link DeleteBucketLifecycleArgs} object. 325 */ 326 default void deleteBucketLifecycle(DeleteBucketLifecycleArgs args) { 327 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 328 .deleteBucketLifecycle(args)); 329 } 330 331 /** 332 * Gets notification configuration of a bucket. 333 * 334 * <pre>Example: {@code 335 * NotificationConfiguration config = 336 * minioClient.getBucketNotification( 337 * GetBucketNotificationArgs.builder().bucket("my-bucketname").build()); 338 * }* 339 * </pre> 340 * 341 * @param args get bucket notification arguments 342 * @return the notification configuration 343 */ 344 default NotificationConfiguration getBucketNotification(GetBucketNotificationArgs args) { 345 return execute(minioClient -> minioClient.getBucketNotification(args)); 346 } 347 348 /** 349 * Sets notification configuration to a bucket. 350 * 351 * <pre>Example: {@code 352 * List<EventType> eventList = new LinkedList<>(); 353 * eventList.add(EventType.OBJECT_CREATED_PUT); 354 * eventList.add(EventType.OBJECT_CREATED_COPY); 355 * 356 * QueueConfiguration queueConfiguration = new QueueConfiguration(); 357 * queueConfiguration.setQueue("arn:minio:sqs::1:webhook"); 358 * queueConfiguration.setEvents(eventList); 359 * queueConfiguration.setPrefixRule("images"); 360 * queueConfiguration.setSuffixRule("pg"); 361 * 362 * List<QueueConfiguration> queueConfigurationList = new LinkedList<>(); 363 * queueConfigurationList.add(queueConfiguration); 364 * 365 * NotificationConfiguration config = new NotificationConfiguration(); 366 * config.setQueueConfigurationList(queueConfigurationList); 367 * 368 * minioClient.setBucketNotification( 369 * SetBucketNotificationArgs.builder().bucket("my-bucketname").config(config).build()); 370 * }* 371 * </pre> 372 * 373 * @param args set bucket notification arguments 374 */ 375 default void setBucketNotification(SetBucketNotificationArgs args) { 376 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 377 .setBucketNotification(args)); 378 } 379 380 /** 381 * Deletes notification configuration of a bucket. 382 * 383 * <pre>Example: {@code 384 * minioClient.deleteBucketNotification( 385 * DeleteBucketNotificationArgs.builder().bucket("my-bucketname").build()); 386 * }* 387 * </pre> 388 * 389 * @param args delete bucket notification arguments 390 */ 391 default void deleteBucketNotification(DeleteBucketNotificationArgs args) { 392 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 393 .deleteBucketNotification(args)); 394 } 395 396 /** 397 * Listens events of object prefix and suffix of a bucket. The returned closable iterator is lazily evaluated hence 398 * its required to iterate to get new records and must be used with try-with-resource to release underneath network 399 * resources. 400 * 401 * <pre>Example: {@code 402 * String[] events = {"s3:ObjectCreated:*", "s3:ObjectAccessed:*"}; 403 * try (CloseableIterator<Result<NotificationRecords>> ci = 404 * minioClient.listenBucketNotification( 405 * ListenBucketNotificationArgs.builder() 406 * .bucket("bucketName") 407 * .prefix("") 408 * .suffix("") 409 * .events(events) 410 * .build())) { 411 * while (ci.hasNext()) { 412 * NotificationRecords records = ci.next().get(); 413 * for (Event event : records.events()) { 414 * System.out.println("Event " + event.eventType() + " occurred at " 415 * + event.eventTime() + " for " + event.bucketName() + "/" 416 * + event.objectName()); 417 * } 418 * } 419 * } 420 * }* 421 * </pre> 422 * 423 * @param args the listen bucket notification arguments 424 * @return lazy closable iterator contains event records 425 */ 426 default CloseableIterator<Result<NotificationRecords>> listenBucketNotification( 427 ListenBucketNotificationArgs args) { 428 return execute(minioClient -> minioClient.listenBucketNotification(args)); 429 } 430 431 /** 432 * Gets bucket policy configuration of a bucket. 433 * 434 * <pre>Example: {@code 435 * String config = 436 * minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket("my-bucketname").build()); 437 * }* 438 * </pre> 439 * 440 * @param args get bucket policy arguments 441 * @return bucket policy configuration as JSON string 442 */ 443 default String getBucketPolicy(GetBucketPolicyArgs args) { 444 return execute(minioClient -> minioClient.getBucketPolicy(args)); 445 } 446 447 /** 448 * Sets bucket policy configuration to a bucket. 449 * 450 * <pre>Example: {@code 451 * // Assume policyJson contains below JSON string; 452 * // { 453 * // "Statement": [ 454 * // { 455 * // "Action": [ 456 * // "s3:GetBucketLocation", 457 * // "s3:ListBucket" 458 * // ], 459 * // "Effect": "Allow", 460 * // "Principal": "*", 461 * // "Resource": "arn:aws:s3:::my-bucketname" 462 * // }, 463 * // { 464 * // "Action": "s3:GetObject", 465 * // "Effect": "Allow", 466 * // "Principal": "*", 467 * // "Resource": "arn:aws:s3:::my-bucketname/myobject*" 468 * // } 469 * // ], 470 * // "Version": "2012-10-17" 471 * // } 472 * // 473 * minioClient.setBucketPolicy( 474 * SetBucketPolicyArgs.builder().bucket("my-bucketname").config(policyJson).build()); 475 * }* 476 * </pre> 477 * 478 * @param args set bucket policy arguments 479 */ 480 default void setBucketPolicy(SetBucketPolicyArgs args) { 481 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 482 .setBucketPolicy(args)); 483 } 484 485 /** 486 * Deletes bucket policy configuration to a bucket. 487 * 488 * <pre>Example: {@code 489 * minioClient.deleteBucketPolicy(DeleteBucketPolicyArgs.builder().bucket("my-bucketname")); 490 * }* 491 * </pre> 492 * 493 * @param args delete bucket policy arguments 494 */ 495 default void deleteBucketPolicy(DeleteBucketPolicyArgs args) { 496 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 497 .deleteBucketPolicy(args)); 498 } 499 500 /** 501 * Gets bucket replication configuration of a bucket. 502 * 503 * <pre>Example: {@code 504 * ReplicationConfiguration config = 505 * minioClient.getBucketReplication( 506 * GetBucketReplicationArgs.builder().bucket("my-bucketname").build()); 507 * }* 508 * </pre> 509 * 510 * @param args get bucket replication arguments 511 * @return the replication configuration 512 */ 513 default Optional<ReplicationConfiguration> getBucketReplication(GetBucketReplicationArgs args) { 514 return execute(minioClient -> Optional.ofNullable(minioClient.getBucketReplication(args))); 515 } 516 517 /** 518 * Sets bucket replication configuration to a bucket. 519 * 520 * <pre>Example: {@code 521 * Map<String, String> tags = new HashMap<>(); 522 * tags.put("key1", "value1"); 523 * tags.put("key2", "value2"); 524 * 525 * ReplicationRule rule = 526 * new ReplicationRule( 527 * new DeleteMarkerReplication(Status.DISABLED), 528 * new ReplicationDestination( 529 * null, null, "REPLACE-WITH-ACTUAL-DESTINATION-BUCKET-ARN", null, null, null, null), 530 * null, 531 * new RuleFilter(new AndOperator("TaxDocs", tags)), 532 * "rule1", 533 * null, 534 * 1, 535 * null, 536 * Status.ENABLED); 537 * 538 * List<ReplicationRule> rules = new LinkedList<>(); 539 * rules.add(rule); 540 * 541 * ReplicationConfiguration config = 542 * new ReplicationConfiguration("REPLACE-WITH-ACTUAL-ROLE", rules); 543 * 544 * minioClient.setBucketReplication( 545 * SetBucketReplicationArgs.builder().bucket("my-bucketname").config(config).build()); 546 * }* 547 * </pre> 548 * 549 * @param args set bucket replication arguments 550 */ 551 default void setBucketReplication(SetBucketReplicationArgs args) { 552 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 553 .setBucketReplication(args)); 554 } 555 556 /** 557 * Deletes bucket replication configuration from a bucket. 558 * 559 * <pre>Example: {@code 560 * minioClient.deleteBucketReplication( 561 * DeleteBucketReplicationArgs.builder().bucket("my-bucketname")); 562 * }* 563 * </pre> 564 * 565 * @param args delete bucket replication arguments 566 */ 567 default void deleteBucketReplication(DeleteBucketReplicationArgs args) { 568 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 569 .deleteBucketReplication(args)); 570 } 571 572 /** 573 * Gets tags of a bucket. 574 * 575 * <pre>Example: {@code 576 * Tags tags = 577 * minioClient.getBucketTags(GetBucketTagsArgs.builder().bucket("my-bucketname").build()); 578 * }* 579 * </pre> 580 * 581 * @param args get bucket tags arguments 582 * @return the tags 583 */ 584 default Tags getBucketTags(GetBucketTagsArgs args) { 585 return execute(minioClient -> minioClient.getBucketTags(args)); 586 } 587 588 /** 589 * Sets tags to a bucket. 590 * 591 * <pre>Example: {@code 592 * Map<String, String> map = new HashMap<>(); 593 * map.put("Project", "Project One"); 594 * map.put("User", "jsmith"); 595 * minioClient.setBucketTags( 596 * SetBucketTagsArgs.builder().bucket("my-bucketname").tags(map).build()); 597 * }* 598 * </pre> 599 * 600 * @param args the set bucket tags arguments 601 */ 602 default void setBucketTags(SetBucketTagsArgs args) { 603 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 604 .setBucketTags(args)); 605 } 606 607 /** 608 * Deletes tags of a bucket. 609 * 610 * <pre>Example: {@code 611 * minioClient.deleteBucketTags(DeleteBucketTagsArgs.builder().bucket("my-bucketname").build()); 612 * }* 613 * </pre> 614 * 615 * @param args the delete bucket tags arguments 616 */ 617 default void deleteBucketTags(DeleteBucketTagsArgs args) { 618 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 619 .deleteBucketTags(args)); 620 } 621 622 /** 623 * Gets versioning configuration of a bucket. 624 * 625 * <pre>Example: {@code 626 * VersioningConfiguration config = 627 * minioClient.getBucketVersioning( 628 * GetBucketVersioningArgs.builder().bucket("my-bucketname").build()); 629 * }* 630 * </pre> 631 * 632 * @param args get bucket version arguments 633 * @return the versioning configuration. 634 */ 635 default VersioningConfiguration getBucketVersioning(GetBucketVersioningArgs args) { 636 return execute(minioClient -> minioClient.getBucketVersioning(args)); 637 } 638 639 /** 640 * Sets versioning configuration of a bucket. 641 * 642 * <pre>Example: {@code 643 * minioClient.setBucketVersioning( 644 * SetBucketVersioningArgs.builder().bucket("my-bucketname").config(config).build()); 645 * }* 646 * </pre> 647 * 648 * @param args set bucket versioning arguments 649 */ 650 default void setBucketVersioning(SetBucketVersioningArgs args) { 651 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 652 .setBucketVersioning(args)); 653 } 654 655 /** 656 * Gets default object retention in a bucket. 657 * 658 * <pre>Example: {@code 659 * ObjectLockConfiguration config = 660 * minioClient.getObjectLockConfiguration( 661 * GetObjectLockConfigurationArgs.builder().bucket("my-bucketname").build()); 662 * System.out.println("Mode: " + config.mode()); 663 * System.out.println( 664 * "Duration: " + config.duration().duration() + " " + config.duration().unit()); 665 * }* 666 * </pre> 667 * 668 * @param args get object retention configuration arguments 669 * @return the default retention configuration 670 */ 671 default ObjectLockConfiguration getObjectLockConfiguration(GetObjectLockConfigurationArgs args) { 672 return execute(minioClient -> minioClient.getObjectLockConfiguration(args)); 673 } 674 675 /** 676 * Sets default object retention in a bucket. 677 * 678 * <pre>Example: {@code 679 * ObjectLockConfiguration config = new ObjectLockConfiguration( 680 * RetentionMode.COMPLIANCE, new RetentionDurationDays(100)); 681 * minioClient.setObjectLockConfiguration( 682 * SetObjectLockConfigurationArgs.builder().bucket("my-bucketname").config(config).build()); 683 * }* 684 * </pre> 685 * 686 * @param args the default object retention configuration arguments 687 */ 688 default void setObjectLockConfiguration(SetObjectLockConfigurationArgs args) { 689 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 690 .setObjectLockConfiguration(args)); 691 } 692 693 /** 694 * Deletes default object retention in a bucket. 695 * 696 * <pre>Example: {@code 697 * minioClient.deleteObjectLockConfiguration( 698 * DeleteObjectLockConfigurationArgs.builder().bucket("my-bucketname").build()); 699 * }* 700 * </pre> 701 * 702 * @param args delete object retention configuration arguments 703 */ 704 default void deleteObjectLockConfiguration(DeleteObjectLockConfigurationArgs args) { 705 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 706 .deleteObjectLockConfiguration(args)); 707 } 708 709 /** 710 * Lists objects information optionally with versions of a bucket. Supports both the versions 1 and 2 of the S3 API. 711 * By default, the <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html">version 2</a> API 712 * is used. <br> 713 * <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html">Version 1</a> 714 * can be used by passing the optional argument {@code useVersion1} as {@code true}. 715 * 716 * <pre>Example: {@code 717 * // Lists objects information. 718 * Iterable<Result<Item>> results = minioClient.listObjects( 719 * ListObjectsArgs.builder().bucket("my-bucketname").build()); 720 * 721 * // Lists objects information recursively. 722 * Iterable<Result<Item>> results = minioClient.listObjects( 723 * ListObjectsArgs.builder().bucket("my-bucketname").recursive(true).build()); 724 * 725 * // Lists maximum 100 objects information those names starts with 'E' and after 726 * // 'ExampleGuide.pdf'. 727 * Iterable<Result<Item>> results = minioClient.listObjects( 728 * ListObjectsArgs.builder() 729 * .bucket("my-bucketname") 730 * .startAfter("ExampleGuide.pdf") 731 * .prefix("E") 732 * .maxKeys(100) 733 * .build()); 734 * 735 * // Lists maximum 100 objects information with version those names starts with 'E' and after 736 * // 'ExampleGuide.pdf'. 737 * Iterable<Result<Item>> results = minioClient.listObjects( 738 * ListObjectsArgs.builder() 739 * .bucket("my-bucketname") 740 * .startAfter("ExampleGuide.pdf") 741 * .prefix("E") 742 * .maxKeys(100) 743 * .includeVersions(true) 744 * .build()); 745 * }* 746 * </pre> 747 * 748 * @param args list objects arguments 749 * @return lazy iterator contains object information 750 */ 751 default Iterable<Result<Item>> listObjects(ListObjectsArgs args) { 752 return execute(minioClient -> minioClient.listObjects(args)); 753 } 754 755 // Object operations 756 757 /** 758 * Uploads data from a stream to an object. 759 * 760 * <pre>Example: {@code 761 * // Upload known sized input stream. 762 * minioClient.putObject( 763 * PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( 764 * inputStream, size, -1) 765 * .contentType("video/mp4") 766 * .build()); 767 * 768 * // Upload unknown sized input stream. 769 * minioClient.putObject( 770 * PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( 771 * inputStream, -1, 10485760) 772 * .contentType("video/mp4") 773 * .build()); 774 * 775 * // Create object ends with '/' (also called as folder or directory). 776 * minioClient.putObject( 777 * PutObjectArgs.builder().bucket("my-bucketname").object("path/to/").stream( 778 * new ByteArrayInputStream(new byte[] {}), 0, -1) 779 * .build()); 780 * 781 * // Upload input stream with headers and user metadata. 782 * Map<String, String> headers = new HashMap<>(); 783 * headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY"); 784 * Map<String, String> userMetadata = new HashMap<>(); 785 * userMetadata.put("My-Project", "Project One"); 786 * minioClient.putObject( 787 * PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( 788 * inputStream, size, -1) 789 * .headers(headers) 790 * .userMetadata(userMetadata) 791 * .build()); 792 * 793 * // Upload input stream with server-side encryption. 794 * minioClient.putObject( 795 * PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream( 796 * inputStream, size, -1) 797 * .sse(sse) 798 * .build()); 799 * }* 800 * </pre> 801 * 802 * @param args put object arguments 803 * @return the object write response 804 */ 805 default ObjectWriteResponse putObject(PutObjectArgs args) { 806 return execute(minioClient -> minioClient.putObject(args)); 807 } 808 809 /** 810 * Uploads data from a file to an object. 811 * 812 * <pre>Example: {@code 813 * // Upload an JSON file. 814 * minioClient.uploadObject( 815 * UploadObjectArgs.builder() 816 * .bucket("my-bucketname").object("my-objectname").filename("person.json").build()); 817 * 818 * // Upload a video file. 819 * minioClient.uploadObject( 820 * UploadObjectArgs.builder() 821 * .bucket("my-bucketname") 822 * .object("my-objectname") 823 * .filename("my-video.avi") 824 * .contentType("video/mp4") 825 * .build()); 826 * }* 827 * </pre> 828 * 829 * @param args upload object arguments 830 * @param deleteMode delete mode 831 * @return the object write response 832 */ 833 default ObjectWriteResponse uploadObject(UploadObjectArgs args, DeleteMode deleteMode) { 834 final Path file = Paths.get(args.filename()); 835 try { 836 return execute(minioClient -> { 837 ObjectWriteResponse response = minioClient.uploadObject(args); 838 if (DeleteMode.ON_SUCCESS == deleteMode) { 839 Files.delete(file); 840 } 841 return response; 842 }); 843 844 } finally { 845 if (DeleteMode.ALWAYS == deleteMode) { 846 execute((MinioClientCallbackWithoutResult) minioClient -> Files.delete(file)); 847 } 848 } 849 } 850 851 /** 852 * Downloads data of a SSE-C encrypted object to file. 853 * 854 * <pre>Example: {@code 855 * minioClient.downloadObject( 856 * GetObjectArgs.builder() 857 * .bucket("my-bucketname") 858 * .object("my-objectname") 859 * .ssec(ssec) 860 * .fileName("my-filename") 861 * .build()); 862 * }* 863 * </pre> 864 * 865 * @param args download object arguments 866 */ 867 default void downloadObject(DownloadObjectArgs args) { 868 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 869 .downloadObject(args)); 870 } 871 872 /** 873 * Gets presigned URL of an object for HTTP method, expiry time and custom request parameters. 874 * 875 * <pre>Example: {@code 876 * // Get presigned URL string to delete 'my-objectname' in 'my-bucketname' and its life time 877 * // is one day. 878 * String url = 879 * minioClient.getPresignedObjectUrl( 880 * GetPresignedObjectUrlArgs.builder() 881 * .method(Method.DELETE) 882 * .bucket("my-bucketname") 883 * .object("my-objectname") 884 * .expiry(24 * 60 * 60) 885 * .build()); 886 * System.out.println(url); 887 * 888 * // Get presigned URL string to upload 'my-objectname' in 'my-bucketname' 889 * // with response-content-type as application/json and life time as one day. 890 * Map<String, String> reqParams = new HashMap<String, String>(); 891 * reqParams.put("response-content-type", "application/json"); 892 * 893 * String url = 894 * minioClient.getPresignedObjectUrl( 895 * GetPresignedObjectUrlArgs.builder() 896 * .method(Method.PUT) 897 * .bucket("my-bucketname") 898 * .object("my-objectname") 899 * .expiry(1, TimeUnit.DAYS) 900 * .extraQueryParams(reqParams) 901 * .build()); 902 * System.out.println(url); 903 * 904 * // Get presigned URL string to download 'my-objectname' in 'my-bucketname' and its life time 905 * // is 2 hours. 906 * String url = 907 * minioClient.getPresignedObjectUrl( 908 * GetPresignedObjectUrlArgs.builder() 909 * .method(Method.GET) 910 * .bucket("my-bucketname") 911 * .object("my-objectname") 912 * .expiry(2, TimeUnit.HOURS) 913 * .build()); 914 * System.out.println(url); 915 * }* 916 * </pre> 917 * 918 * @param args get pre-signed object url arguments 919 * @return the pre-signed URL 920 */ 921 default String getPresignedObjectUrl(GetPresignedObjectUrlArgs args) { 922 return execute(minioClient -> minioClient.getPresignedObjectUrl(args)); 923 } 924 925 /** 926 * Gets form-data of {@link PostPolicy} of an object to upload its data using POST method. 927 * 928 * <pre>Example: {@code 929 * // Create new post policy for 'my-bucketname' with 7 days expiry from now. 930 * PostPolicy policy = new PostPolicy("my-bucketname", ZonedDateTime.now().plusDays(7)); 931 * 932 * // Add condition that 'key' (object name) equals to 'my-objectname'. 933 * policy.addEqualsCondition("key", "my-objectname"); 934 * 935 * // Add condition that 'Content-Type' starts with 'image/'. 936 * policy.addStartsWithCondition("Content-Type", "image/"); 937 * 938 * // Add condition that 'content-length-range' is between 64kiB to 10MiB. 939 * policy.addContentLengthRangeCondition(64 * 1024, 10 * 1024 * 1024); 940 * 941 * Map<String, String> formData = minioClient.getPresignedPostFormData(policy); 942 * 943 * // Upload an image using POST object with form-data. 944 * MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); 945 * multipartBuilder.setType(MultipartBody.FORM); 946 * for (Map.Entry<String, String> entry : formData.entrySet()) { 947 * multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue()); 948 * } 949 * multipartBuilder.addFormDataPart("key", "my-objectname"); 950 * multipartBuilder.addFormDataPart("Content-Type", "image/png"); 951 * 952 * // "file" must be added at last. 953 * multipartBuilder.addFormDataPart( 954 * "file", "my-objectname", RequestBody.create(new File("Pictures/avatar.png"), null)); 955 * 956 * Request request = 957 * new Request.Builder() 958 * .url("https://play.min.io/my-bucketname") 959 * .post(multipartBuilder.build()) 960 * .build(); 961 * OkHttpClient httpClient = new OkHttpClient().newBuilder().build(); 962 * Response response = httpClient.newCall(request).execute(); 963 * if (response.isSuccessful()) { 964 * System.out.println("Pictures/avatar.png is uploaded successfully using POST object"); 965 * } else { 966 * System.out.println("Failed to upload Pictures/avatar.png"); 967 * } 968 * }* 969 * </pre> 970 * 971 * @param policy post policy of an object 972 * @return contains form-data to upload an object using POST method 973 */ 974 default Map<String, String> getPresignedPostFormData(PostPolicy policy) { 975 return execute(minioClient -> minioClient.getPresignedPostFormData(policy)); 976 } 977 978 /** 979 * Gets information of an object. 980 * 981 * <pre>Example: {@code 982 * // Get information of an object. 983 * ObjectStat objectStat = 984 * minioClient.statObject( 985 * StatObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); 986 * 987 * // Get information of SSE-C encrypted object. 988 * ObjectStat objectStat = 989 * minioClient.statObject( 990 * StatObjectArgs.builder() 991 * .bucket("my-bucketname") 992 * .object("my-objectname") 993 * .ssec(ssec) 994 * .build()); 995 * 996 * // Get information of a versioned object. 997 * ObjectStat objectStat = 998 * minioClient.statObject( 999 * StatObjectArgs.builder() 1000 * .bucket("my-bucketname") 1001 * .object("my-objectname") 1002 * .versionId("version-id") 1003 * .build()); 1004 * 1005 * // Get information of a SSE-C encrypted versioned object. 1006 * ObjectStat objectStat = 1007 * minioClient.statObject( 1008 * StatObjectArgs.builder() 1009 * .bucket("my-bucketname") 1010 * .object("my-objectname") 1011 * .versionId("version-id") 1012 * .ssec(ssec) 1013 * .build()); 1014 * }* 1015 * </pre> 1016 * 1017 * @param args status object arguments 1018 * @return populated object information and metadata 1019 */ 1020 default StatObjectResponse statObject(StatObjectArgs args) { 1021 return execute(minioClient -> minioClient.statObject(args)); 1022 } 1023 1024 /** 1025 * Check whether an object exists or not. 1026 * 1027 * @param args status object arguments 1028 * @return {@code true} if the object exists, otherwise {@code false} 1029 */ 1030 default boolean objectExists(StatObjectArgs args) { 1031 try { 1032 return statObject(args) != null; 1033 } catch (MinioException e) { 1034 if (404 == e.status()) { 1035 return false; 1036 } 1037 throw e; 1038 } 1039 } 1040 1041 /** 1042 * Gets data from offset to length of a SSE-C encrypted object. Returned {@link InputStream} must be closed after use 1043 * to release network resources. 1044 * 1045 * <pre>Example: {@code 1046 * try (InputStream stream = 1047 * minioClient.getObject( 1048 * GetObjectArgs.builder() 1049 * .bucket("my-bucketname") 1050 * .object("my-objectname") 1051 * .offset(offset) 1052 * .length(len) 1053 * .ssec(ssec) 1054 * .build() 1055 * ) { 1056 * // Read data from stream 1057 * } 1058 * }* 1059 * </pre> 1060 * 1061 * @param args the get object arguments 1062 * @return the input stream 1063 */ 1064 default InputStream getObject(GetObjectArgs args) { 1065 return execute(minioClient -> minioClient.getObject(args)); 1066 } 1067 1068 /** 1069 * Selects content of an object by SQL expression. 1070 * 1071 * <pre>Example: {@code 1072 * String sqlExpression = "select * from S3Object"; 1073 * InputSerialization is = 1074 * new InputSerialization(null, false, null, null, FileHeaderInfo.USE, null, null, 1075 * null); 1076 * OutputSerialization os = 1077 * new OutputSerialization(null, null, null, QuoteFields.ASNEEDED, null); 1078 * SelectResponseStream stream = 1079 * minioClient.selectObjectContent( 1080 * SelectObjectContentArgs.builder() 1081 * .bucket("my-bucketname") 1082 * .object("my-objectname") 1083 * .sqlExpression(sqlExpression) 1084 * .inputSerialization(is) 1085 * .outputSerialization(os) 1086 * .requestProgress(true) 1087 * .build()); 1088 * 1089 * byte[] buf = new byte[512]; 1090 * int bytesRead = stream.read(buf, 0, buf.length); 1091 * System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8)); 1092 * 1093 * Stats stats = stream.stats(); 1094 * System.out.println("bytes scanned: " + stats.bytesScanned()); 1095 * System.out.println("bytes processed: " + stats.bytesProcessed()); 1096 * System.out.println("bytes returned: " + stats.bytesReturned()); 1097 * 1098 * stream.close(); 1099 * }* 1100 * </pre> 1101 * 1102 * @param args the select object content arguments 1103 * @return the select response stream 1104 */ 1105 default SelectResponseStream selectObjectContent(SelectObjectContentArgs args) { 1106 return execute(minioClient -> minioClient.selectObjectContent(args)); 1107 } 1108 1109 /** 1110 * Removes an object. 1111 * 1112 * <pre>Example: {@code 1113 * // Remove object. 1114 * minioClient.removeObject( 1115 * RemoveObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build()); 1116 * 1117 * // Remove versioned object. 1118 * minioClient.removeObject( 1119 * RemoveObjectArgs.builder() 1120 * .bucket("my-bucketname") 1121 * .object("my-versioned-objectname") 1122 * .versionId("my-versionid") 1123 * .build()); 1124 * 1125 * // Remove versioned object bypassing Governance mode. 1126 * minioClient.removeObject( 1127 * RemoveObjectArgs.builder() 1128 * .bucket("my-bucketname") 1129 * .object("my-versioned-objectname") 1130 * .versionId("my-versionid") 1131 * .bypassRetentionMode(true) 1132 * .build()); 1133 * }* 1134 * </pre> 1135 * 1136 * @param args remove object arguments 1137 */ 1138 default void removeObject(RemoveObjectArgs args) { 1139 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 1140 .removeObject(args)); 1141 } 1142 1143 /** 1144 * Removes multiple objects lazily. Its required to iterate the returned Iterable to perform removal. 1145 * 1146 * <pre>Example: {@code 1147 * List<DeleteObject> objects = new LinkedList<>(); 1148 * objects.add(new DeleteObject("my-objectname1")); 1149 * objects.add(new DeleteObject("my-objectname2")); 1150 * objects.add(new DeleteObject("my-objectname3")); 1151 * Iterable<Result<DeleteError>> results = 1152 * minioClient.removeObjects( 1153 * RemoveObjectsArgs.builder().bucket("my-bucketname").objects(objects).build()); 1154 * for (Result<DeleteError> result : results) { 1155 * DeleteError error = errorResult.get(); 1156 * System.out.println( 1157 * "Error in deleting object " + error.objectName() + "; " + error.message()); 1158 * } 1159 * }* 1160 * </pre> 1161 * 1162 * @param args the objects to remove 1163 * @return lazy iterator contains object removal status 1164 */ 1165 default Iterable<Result<DeleteError>> removeObjects(RemoveObjectsArgs args) { 1166 return execute(minioClient -> minioClient.removeObjects(args)); 1167 } 1168 1169 /** 1170 * Creates an object by combining data from different source objects using server-side copy. 1171 * 1172 * <pre>Example: {@code 1173 * List<ComposeSource> sourceObjectList = new ArrayList<ComposeSource>(); 1174 * 1175 * sourceObjectList.add( 1176 * ComposeSource.builder().bucket("my-job-bucket").object("my-objectname-part-one").build()); 1177 * sourceObjectList.add( 1178 * ComposeSource.builder().bucket("my-job-bucket").object("my-objectname-part-two").build()); 1179 * sourceObjectList.add( 1180 * ComposeSource.builder().bucket("my-job-bucket").object("my-objectname-part-three").build()); 1181 * 1182 * // Create my-bucketname/my-objectname by combining source object list. 1183 * minioClient.composeObject( 1184 * ComposeObjectArgs.builder() 1185 * .bucket("my-bucketname") 1186 * .object("my-objectname") 1187 * .sources(sourceObjectList) 1188 * .build()); 1189 * }* 1190 * </pre> 1191 * 1192 * @param args compose object arguments 1193 * @return the object write response 1194 */ 1195 default ObjectWriteResponse composeObject(ComposeObjectArgs args) { 1196 return execute(minioClient -> minioClient.composeObject(args)); 1197 } 1198 1199 /** 1200 * Creates an object by server-side copying data from another object. 1201 * 1202 * @param args copy object arguments 1203 * @return the object write response 1204 */ 1205 default ObjectWriteResponse copyObject(CopyObjectArgs args) { 1206 return execute(minioClient -> minioClient.copyObject(args)); 1207 } 1208 1209 /** 1210 * Gets retention configuration of an object. 1211 * 1212 * <pre>Example: {@code 1213 * Retention retention = 1214 * minioClient.getObjectRetention(GetObjectRetentionArgs.builder() 1215 * .bucket(bucketName) 1216 * .object(objectName) 1217 * .versionId(versionId) 1218 * .build());); 1219 * System.out.println( 1220 * "mode: " + retention.mode() + "until: " + retention.retainUntilDate()); 1221 * }* 1222 * </pre> 1223 * 1224 * @param args get object retention arguments 1225 * @return object retention configuration 1226 */ 1227 default Retention getObjectRetention(GetObjectRetentionArgs args) { 1228 return execute(minioClient -> minioClient.getObjectRetention(args)); 1229 } 1230 1231 /** 1232 * Sets retention configuration to an object. 1233 * 1234 * <pre>Example: {@code 1235 * Retention retention = new Retention( 1236 * RetentionMode.COMPLIANCE, ZonedDateTime.now().plusYears(1)); 1237 * minioClient.setObjectRetention( 1238 * SetObjectRetentionArgs.builder() 1239 * .bucket("my-bucketname") 1240 * .object("my-objectname") 1241 * .config(config) 1242 * .bypassGovernanceMode(true) 1243 * .build()); 1244 * }* 1245 * </pre> 1246 * 1247 * @param args set object retention arguments 1248 */ 1249 default void setObjectRetention(SetObjectRetentionArgs args) { 1250 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 1251 .setObjectRetention(args)); 1252 } 1253 1254 /** 1255 * Gets tags of an object. 1256 * 1257 * <pre>Example: {@code 1258 * Tags tags = 1259 * minioClient.getObjectTags( 1260 * GetObjectTagsArgs.builder().bucket("my-bucketname").object("my-objectname").build()); 1261 * }* 1262 * </pre> 1263 * 1264 * @param args get object tags arguments 1265 * @return the tags 1266 */ 1267 default Tags getObjectTags(GetObjectTagsArgs args) { 1268 return execute(minioClient -> minioClient.getObjectTags(args)); 1269 } 1270 1271 /** 1272 * Sets tags to an object. 1273 * 1274 * <pre>Example: {@code 1275 * Map<String, String> map = new HashMap<>(); 1276 * map.put("Project", "Project One"); 1277 * map.put("User", "jsmith"); 1278 * minioClient.setObjectTags( 1279 * SetObjectTagsArgs.builder() 1280 * .bucket("my-bucketname") 1281 * .object("my-objectname") 1282 * .tags((map) 1283 * .build()); 1284 * }* 1285 * </pre> 1286 * 1287 * @param args set object tags arguments 1288 */ 1289 default void setObjectTags(SetObjectTagsArgs args) { 1290 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 1291 .setObjectTags(args)); 1292 } 1293 1294 /** 1295 * Deletes tags of an object. 1296 * 1297 * <pre>Example: {@code 1298 * minioClient.deleteObjectTags( 1299 * DeleteObjectTags.builder().bucket("my-bucketname").object("my-objectname").build()); 1300 * }* 1301 * </pre> 1302 * 1303 * @param args delete object tags arguments 1304 */ 1305 default void deleteObjectTags(DeleteObjectTagsArgs args) { 1306 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 1307 .deleteObjectTags(args)); 1308 } 1309 1310 /** 1311 * Returns true if legal hold is enabled on an object. 1312 * 1313 * <pre>Example: {@code 1314 * boolean status = 1315 * s3Client.isObjectLegalHoldEnabled( 1316 * IsObjectLegalHoldEnabledArgs.builder() 1317 * .bucket("my-bucketname") 1318 * .object("my-objectname") 1319 * .versionId("object-versionId") 1320 * .build()); 1321 * if (status) { 1322 * System.out.println("Legal hold is on"); 1323 * } else { 1324 * System.out.println("Legal hold is off"); 1325 * } 1326 * }* 1327 * </pre> 1328 * 1329 * @param args is object legel hold enabled arguments 1330 * @return true if legal hold is enabled 1331 */ 1332 default boolean isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs args) { 1333 return execute(minioClient -> minioClient.isObjectLegalHoldEnabled(args)); 1334 } 1335 1336 /** 1337 * Enables legal hold on an object. 1338 * 1339 * <pre>Example: {@code 1340 * minioClient.enableObjectLegalHold( 1341 * EnableObjectLegalHoldArgs.builder() 1342 * .bucket("my-bucketname") 1343 * .object("my-objectname") 1344 * .versionId("object-versionId") 1345 * .build()); 1346 * }* 1347 * </pre> 1348 * 1349 * @param args enable object legal hold arguments 1350 */ 1351 default void enableObjectLegalHold(EnableObjectLegalHoldArgs args) { 1352 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 1353 .enableObjectLegalHold(args)); 1354 } 1355 1356 /** 1357 * Disables legal hold on an object. 1358 * 1359 * <pre>Example: {@code 1360 * minioClient.disableObjectLegalHold( 1361 * DisableObjectLegalHoldArgs.builder() 1362 * .bucket("my-bucketname") 1363 * .object("my-objectname") 1364 * .versionId("object-versionId") 1365 * .build()); 1366 * }* 1367 * </pre> 1368 * 1369 * @param args disable object legal hold arguments 1370 */ 1371 default void disableObjectLegalHold(DisableObjectLegalHoldArgs args) { 1372 execute((MinioClientCallbackWithoutResult) minioClient -> minioClient 1373 .disableObjectLegalHold(args)); 1374 } 1375 1376 }