@@ -454,26 +454,37 @@ public Page<Bucket> list(BucketListOption... options) {
454454 Opts <BucketListOpt > opts = Opts .unwrap (options ).prepend (defaultOpts ).prepend (ALL_BUCKET_FIELDS );
455455 GrpcCallContext grpcCallContext =
456456 opts .grpcMetadataMapper ().apply (GrpcCallContext .createDefault ());
457+
457458 ListBucketsRequest request =
458459 defaultProjectId
459460 .get ()
460461 .listBuckets ()
461462 .andThen (opts .listBucketsRequest ())
462463 .apply (ListBucketsRequest .newBuilder ())
463464 .build ();
464- try {
465- GrpcCallContext merge = Utils .merge (grpcCallContext , Retrying .newCallContext ());
466- return retrier .run (
467- retryAlgorithmManager .getFor (request ),
468- () -> storageClient .listBucketsPagedCallable ().call (request , merge ),
469- resp ->
470- new TransformingPageDecorator <>(
471- resp .getPage (),
472- syntaxDecoders .bucket .andThen (opts .clearBucketFields ()),
473- retrier ,
474- retryAlgorithmManager .getFor (request )));
475- } catch (Exception e ) {
476- throw StorageException .coalesce (e );
465+
466+ if (!request .getReturnPartialSuccess ()) {
467+ try {
468+ GrpcCallContext merge = Utils .merge (grpcCallContext , Retrying .newCallContext ());
469+ return retrier .run (
470+ retryAlgorithmManager .getFor (request ),
471+ () -> storageClient .listBucketsPagedCallable ().call (request , merge ),
472+ resp ->
473+ new TransformingPageDecorator <>(
474+ resp .getPage (),
475+ syntaxDecoders .bucket .andThen (opts .clearBucketFields ()),
476+ retrier ,
477+ retryAlgorithmManager .getFor (request )));
478+ } catch (Exception e ) {
479+ throw StorageException .coalesce (e );
480+ }
481+ } else {
482+ try {
483+ com .google .storage .v2 .ListBucketsResponse response = listBuckets (grpcCallContext , request );
484+ return new ListBucketsWithPartialSuccessPage (grpcCallContext , request , response , opts );
485+ } catch (Exception e ) {
486+ throw StorageException .coalesce (e );
487+ }
477488 }
478489 }
479490
@@ -1619,6 +1630,78 @@ public Iterable<Blob> getValues() {
16191630 }
16201631 }
16211632
1633+ private final class ListBucketsWithPartialSuccessPage implements Page <Bucket > {
1634+
1635+ private final GrpcCallContext ctx ;
1636+ private final ListBucketsRequest req ;
1637+ private final com .google .storage .v2 .ListBucketsResponse resp ;
1638+ private final Opts <BucketListOpt > opts ;
1639+
1640+ private ListBucketsWithPartialSuccessPage (
1641+ GrpcCallContext ctx ,
1642+ ListBucketsRequest req ,
1643+ com .google .storage .v2 .ListBucketsResponse resp ,
1644+ Opts <BucketListOpt > opts ) {
1645+ this .ctx = ctx ;
1646+ this .req = req ;
1647+ this .resp = resp ;
1648+ this .opts = opts ;
1649+ }
1650+
1651+ @ Override
1652+ public boolean hasNextPage () {
1653+ return !resp .getNextPageToken ().isEmpty ();
1654+ }
1655+
1656+ @ Override
1657+ public String getNextPageToken () {
1658+ return resp .getNextPageToken ();
1659+ }
1660+
1661+ @ Override
1662+ public Page <Bucket > getNextPage () {
1663+ if (!hasNextPage ()) {
1664+ return null ;
1665+ }
1666+ ListBucketsRequest nextPageReq =
1667+ req .toBuilder ().setPageToken (resp .getNextPageToken ()).build ();
1668+ try {
1669+ com .google .storage .v2 .ListBucketsResponse nextPageResp = listBuckets (ctx , nextPageReq );
1670+ return new ListBucketsWithPartialSuccessPage (ctx , nextPageReq , nextPageResp , opts );
1671+ } catch (Exception e ) {
1672+ throw StorageException .coalesce (e );
1673+ }
1674+ }
1675+
1676+ @ Override
1677+ public Iterable <Bucket > getValues () {
1678+ Decoder <com .google .storage .v2 .Bucket , Bucket > bucketDecoder =
1679+ syntaxDecoders .bucket .andThen (opts .clearBucketFields ());
1680+ Stream <Bucket > reachable = resp .getBucketsList ().stream ().map (bucketDecoder ::decode );
1681+ Stream <Bucket > unreachable =
1682+ resp .getUnreachableList ().stream ()
1683+ .map (
1684+ name -> {
1685+ String decoded = bucketNameCodec .decode (name );
1686+ return BucketInfo .newBuilder (decoded )
1687+ .setIsUnreachable (true )
1688+ .build ()
1689+ .asBucket (GrpcStorageImpl .this );
1690+ });
1691+ return Streams .concat (reachable , unreachable ).collect (ImmutableList .toImmutableList ());
1692+ }
1693+
1694+ @ Override
1695+ public Iterable <Bucket > iterateAll () {
1696+ Page <Bucket > curr = this ;
1697+ return () ->
1698+ streamIterate (curr , p -> p != null && p .hasNextPage (), Page ::getNextPage )
1699+ .filter (Objects ::nonNull )
1700+ .flatMap (p -> StreamSupport .stream (p .getValues ().spliterator (), false ))
1701+ .iterator ();
1702+ }
1703+ }
1704+
16221705 static final class TransformingPageDecorator <
16231706 RequestT ,
16241707 ResponseT ,
@@ -1858,6 +1941,15 @@ private SourceObject sourceObjectEncode(SourceBlob from) {
18581941 return to .build ();
18591942 }
18601943
1944+ private com .google .storage .v2 .ListBucketsResponse listBuckets (
1945+ GrpcCallContext grpcCallContext , ListBucketsRequest request ) {
1946+ GrpcCallContext merge = Utils .merge (grpcCallContext , Retrying .newCallContext ());
1947+ return retrier .run (
1948+ retryAlgorithmManager .getFor (request ),
1949+ () -> storageClient .listBucketsCallable ().call (request , merge ),
1950+ Decoder .identity ());
1951+ }
1952+
18611953 private com .google .storage .v2 .Bucket getBucketWithDefaultAcls (String bucketName ) {
18621954 Fields fields =
18631955 UnifiedOpts .fields (
0 commit comments