19
19
import static com .google .cloud .storage .ByteSizeConstants ._16MiB ;
20
20
import static com .google .cloud .storage .ByteSizeConstants ._256KiB ;
21
21
import static com .google .cloud .storage .GrpcToHttpStatusCodeTranslation .resultRetryAlgorithmToCodes ;
22
+ import static com .google .cloud .storage .StorageV2ProtoUtils .bucketAclEntityOrAltEq ;
22
23
import static com .google .cloud .storage .StorageV2ProtoUtils .objectAclEntityOrAltEq ;
23
24
import static com .google .cloud .storage .Utils .bucketNameCodec ;
24
25
import static com .google .cloud .storage .Utils .ifNonNull ;
76
77
import com .google .iam .v1 .TestIamPermissionsRequest ;
77
78
import com .google .protobuf .ByteString ;
78
79
import com .google .protobuf .FieldMask ;
80
+ import com .google .storage .v2 .BucketAccessControl ;
79
81
import com .google .storage .v2 .ComposeObjectRequest ;
80
82
import com .google .storage .v2 .ComposeObjectRequest .SourceObject ;
81
83
import com .google .storage .v2 .CreateBucketRequest ;
@@ -152,6 +154,7 @@ final class GrpcStorageImpl extends BaseService<StorageOptions> implements Stora
152
154
StandardOpenOption .WRITE ,
153
155
StandardOpenOption .CREATE ,
154
156
StandardOpenOption .TRUNCATE_EXISTING );
157
+ private static final BucketSourceOption [] EMPTY_BUCKET_SOURCE_OPTIONS = new BucketSourceOption [0 ];
155
158
156
159
final StorageClient storageClient ;
157
160
final GrpcConversions codecs ;
@@ -853,63 +856,148 @@ public List<Boolean> delete(Iterable<BlobId> blobIds) {
853
856
854
857
@ Override
855
858
public Acl getAcl (String bucket , Entity entity , BucketSourceOption ... options ) {
856
- return throwNotYetImplemented (
857
- fmtMethodName ("getAcl" , String .class , Entity .class , BucketSourceOption [].class ));
859
+ try {
860
+ Opts <BucketSourceOpt > opts = Opts .unwrap (options );
861
+ com .google .storage .v2 .Bucket resp = getBucketWithAcls (bucket , opts );
862
+
863
+ Predicate <BucketAccessControl > entityPredicate =
864
+ bucketAclEntityOrAltEq (codecs .entity ().encode (entity ));
865
+
866
+ Optional <BucketAccessControl > first =
867
+ resp .getAclList ().stream ().filter (entityPredicate ).findFirst ();
868
+
869
+ // HttpStorageRpc defaults to null if Not Found
870
+ return first .map (codecs .bucketAcl ()::decode ).orElse (null );
871
+ } catch (NotFoundException e ) {
872
+ return null ;
873
+ } catch (StorageException se ) {
874
+ if (se .getCode () == 404 ) {
875
+ return null ;
876
+ } else {
877
+ throw se ;
878
+ }
879
+ }
858
880
}
859
881
860
882
@ Override
861
883
public Acl getAcl (String bucket , Entity entity ) {
862
- return throwNotYetImplemented ( fmtMethodName ( " getAcl" , String . class , Entity . class ) );
884
+ return getAcl ( bucket , entity , EMPTY_BUCKET_SOURCE_OPTIONS );
863
885
}
864
886
865
887
@ Override
866
888
public boolean deleteAcl (String bucket , Entity entity , BucketSourceOption ... options ) {
867
- return throwNotYetImplemented (
868
- fmtMethodName ("deleteAcl" , String .class , Entity .class , BucketSourceOption [].class ));
889
+ try {
890
+ Opts <BucketSourceOpt > opts = Opts .unwrap (options );
891
+ com .google .storage .v2 .Bucket resp = getBucketWithAcls (bucket , opts );
892
+ String encode = codecs .entity ().encode (entity );
893
+
894
+ Predicate <BucketAccessControl > entityPredicate = bucketAclEntityOrAltEq (encode );
895
+
896
+ List <BucketAccessControl > currentAcls = resp .getAclList ();
897
+ ImmutableList <BucketAccessControl > newAcls =
898
+ currentAcls .stream ()
899
+ .filter (entityPredicate .negate ())
900
+ .collect (ImmutableList .toImmutableList ());
901
+ if (newAcls .equals (currentAcls )) {
902
+ // we didn't actually filter anything out, no need to send an RPC, simply return false
903
+ return false ;
904
+ }
905
+ long metageneration = resp .getMetageneration ();
906
+
907
+ UpdateBucketRequest req = createUpdateAclRequest (bucket , newAcls , metageneration );
908
+
909
+ com .google .storage .v2 .Bucket updateResult = updateBucket (req );
910
+ // read the response to ensure there is no longer an acl for the specified entity
911
+ Optional <BucketAccessControl > first =
912
+ updateResult .getAclList ().stream ().filter (entityPredicate ).findFirst ();
913
+ return !first .isPresent ();
914
+ } catch (NotFoundException e ) {
915
+ // HttpStorageRpc returns false if the bucket doesn't exist :(
916
+ return false ;
917
+ } catch (StorageException se ) {
918
+ if (se .getCode () == 404 ) {
919
+ return false ;
920
+ } else {
921
+ throw se ;
922
+ }
923
+ }
869
924
}
870
925
871
926
@ Override
872
927
public boolean deleteAcl (String bucket , Entity entity ) {
873
- return throwNotYetImplemented ( fmtMethodName ( " deleteAcl" , String . class , Entity . class ) );
928
+ return deleteAcl ( bucket , entity , EMPTY_BUCKET_SOURCE_OPTIONS );
874
929
}
875
930
876
931
@ Override
877
932
public Acl createAcl (String bucket , Acl acl , BucketSourceOption ... options ) {
878
- return throwNotYetImplemented (
879
- fmtMethodName ("createAcl" , String .class , Acl .class , BucketSourceOption [].class ));
933
+ return updateAcl (bucket , acl , options );
880
934
}
881
935
882
936
@ Override
883
937
public Acl createAcl (String bucket , Acl acl ) {
884
- return throwNotYetImplemented ( fmtMethodName ( " createAcl" , String . class , Acl . class ) );
938
+ return createAcl ( bucket , acl , EMPTY_BUCKET_SOURCE_OPTIONS );
885
939
}
886
940
887
941
@ Override
888
942
public Acl updateAcl (String bucket , Acl acl , BucketSourceOption ... options ) {
889
- return throwNotYetImplemented (
890
- fmtMethodName ("updateAcl" , String .class , Acl .class , BucketSourceOption [].class ));
943
+ try {
944
+ Opts <BucketSourceOpt > opts = Opts .unwrap (options );
945
+ com .google .storage .v2 .Bucket resp = getBucketWithAcls (bucket , opts );
946
+ BucketAccessControl encode = codecs .bucketAcl ().encode (acl );
947
+ String entity = encode .getEntity ();
948
+
949
+ Predicate <BucketAccessControl > entityPredicate = bucketAclEntityOrAltEq (entity );
950
+
951
+ ImmutableList <BucketAccessControl > newDefaultAcls =
952
+ Streams .concat (
953
+ resp .getAclList ().stream ().filter (entityPredicate .negate ()), Stream .of (encode ))
954
+ .collect (ImmutableList .toImmutableList ());
955
+
956
+ UpdateBucketRequest req =
957
+ createUpdateAclRequest (bucket , newDefaultAcls , resp .getMetageneration ());
958
+
959
+ com .google .storage .v2 .Bucket updateResult = updateBucket (req );
960
+
961
+ Optional <Acl > first =
962
+ updateResult .getAclList ().stream ()
963
+ .filter (entityPredicate )
964
+ .findFirst ()
965
+ .map (codecs .bucketAcl ()::decode );
966
+
967
+ return first .orElseThrow (
968
+ () -> new StorageException (0 , "Acl update call success, but not in response" ));
969
+ } catch (NotFoundException e ) {
970
+ throw StorageException .coalesce (e );
971
+ }
891
972
}
892
973
893
974
@ Override
894
975
public Acl updateAcl (String bucket , Acl acl ) {
895
- return throwNotYetImplemented ( fmtMethodName ( " updateAcl" , String . class , Acl . class ) );
976
+ return updateAcl ( bucket , acl , EMPTY_BUCKET_SOURCE_OPTIONS );
896
977
}
897
978
898
979
@ Override
899
980
public List <Acl > listAcls (String bucket , BucketSourceOption ... options ) {
900
- return throwNotYetImplemented (
901
- fmtMethodName ("listAcls" , String .class , BucketSourceOption [].class ));
981
+ try {
982
+ Opts <BucketSourceOpt > opts = Opts .unwrap (options );
983
+ com .google .storage .v2 .Bucket resp = getBucketWithAcls (bucket , opts );
984
+ return resp .getAclList ().stream ()
985
+ .map (codecs .bucketAcl ()::decode )
986
+ .collect (ImmutableList .toImmutableList ());
987
+ } catch (NotFoundException e ) {
988
+ throw StorageException .coalesce (e );
989
+ }
902
990
}
903
991
904
992
@ Override
905
993
public List <Acl > listAcls (String bucket ) {
906
- return throwNotYetImplemented ( fmtMethodName ( " listAcls" , String . class ) );
994
+ return listAcls ( bucket , EMPTY_BUCKET_SOURCE_OPTIONS );
907
995
}
908
996
909
997
@ Override
910
998
public Acl getDefaultAcl (String bucket , Entity entity ) {
911
999
try {
912
- com .google .storage .v2 .Bucket resp = getBucketDefaultAcls (bucket );
1000
+ com .google .storage .v2 .Bucket resp = getBucketWithDefaultAcls (bucket );
913
1001
914
1002
Predicate <ObjectAccessControl > entityPredicate =
915
1003
objectAclEntityOrAltEq (codecs .entity ().encode (entity ));
@@ -933,7 +1021,7 @@ public Acl getDefaultAcl(String bucket, Entity entity) {
933
1021
@ Override
934
1022
public boolean deleteDefaultAcl (String bucket , Entity entity ) {
935
1023
try {
936
- com .google .storage .v2 .Bucket resp = getBucketDefaultAcls (bucket );
1024
+ com .google .storage .v2 .Bucket resp = getBucketWithDefaultAcls (bucket );
937
1025
String encode = codecs .entity ().encode (entity );
938
1026
939
1027
Predicate <ObjectAccessControl > entityPredicate = objectAclEntityOrAltEq (encode );
@@ -949,7 +1037,8 @@ public boolean deleteDefaultAcl(String bucket, Entity entity) {
949
1037
}
950
1038
long metageneration = resp .getMetageneration ();
951
1039
952
- UpdateBucketRequest req = createUpdateRequest (bucket , newDefaultAcls , metageneration );
1040
+ UpdateBucketRequest req =
1041
+ createUpdateDefaultAclRequest (bucket , newDefaultAcls , metageneration );
953
1042
954
1043
com .google .storage .v2 .Bucket updateResult = updateBucket (req );
955
1044
// read the response to ensure there is no longer an acl for the specified entity
@@ -976,7 +1065,7 @@ public Acl createDefaultAcl(String bucket, Acl acl) {
976
1065
@ Override
977
1066
public Acl updateDefaultAcl (String bucket , Acl acl ) {
978
1067
try {
979
- com .google .storage .v2 .Bucket resp = getBucketDefaultAcls (bucket );
1068
+ com .google .storage .v2 .Bucket resp = getBucketWithDefaultAcls (bucket );
980
1069
ObjectAccessControl encode = codecs .objectAcl ().encode (acl );
981
1070
String entity = encode .getEntity ();
982
1071
@@ -989,7 +1078,7 @@ public Acl updateDefaultAcl(String bucket, Acl acl) {
989
1078
.collect (ImmutableList .toImmutableList ());
990
1079
991
1080
UpdateBucketRequest req =
992
- createUpdateRequest (bucket , newDefaultAcls , resp .getMetageneration ());
1081
+ createUpdateDefaultAclRequest (bucket , newDefaultAcls , resp .getMetageneration ());
993
1082
994
1083
com .google .storage .v2 .Bucket updateResult = updateBucket (req );
995
1084
@@ -1009,7 +1098,7 @@ public Acl updateDefaultAcl(String bucket, Acl acl) {
1009
1098
@ Override
1010
1099
public List <Acl > listDefaultAcls (String bucket ) {
1011
1100
try {
1012
- com .google .storage .v2 .Bucket resp = getBucketDefaultAcls (bucket );
1101
+ com .google .storage .v2 .Bucket resp = getBucketWithDefaultAcls (bucket );
1013
1102
return resp .getDefaultObjectAclList ().stream ()
1014
1103
.map (codecs .objectAcl ()::decode )
1015
1104
.collect (ImmutableList .toImmutableList ());
@@ -1481,7 +1570,7 @@ private SourceObject sourceObjectEncode(SourceBlob from) {
1481
1570
return to .build ();
1482
1571
}
1483
1572
1484
- private com .google .storage .v2 .Bucket getBucketDefaultAcls (String bucketName ) {
1573
+ private com .google .storage .v2 .Bucket getBucketWithDefaultAcls (String bucketName ) {
1485
1574
Fields fields =
1486
1575
UnifiedOpts .fields (
1487
1576
ImmutableSet .of (
@@ -1503,6 +1592,25 @@ private com.google.storage.v2.Bucket getBucketDefaultAcls(String bucketName) {
1503
1592
Decoder .identity ());
1504
1593
}
1505
1594
1595
+ private com .google .storage .v2 .Bucket getBucketWithAcls (
1596
+ String bucketName , Opts <BucketSourceOpt > opts ) {
1597
+ Fields fields =
1598
+ UnifiedOpts .fields (ImmutableSet .of (BucketField .ACL , BucketField .METAGENERATION ));
1599
+ GrpcCallContext grpcCallContext = GrpcCallContext .createDefault ();
1600
+ Mapper <GetBucketRequest .Builder > mapper = opts .getBucketsRequest ().andThen (fields .getBucket ());
1601
+ GetBucketRequest req =
1602
+ mapper
1603
+ .apply (GetBucketRequest .newBuilder ())
1604
+ .setName (bucketNameCodec .encode (bucketName ))
1605
+ .build ();
1606
+
1607
+ return Retrying .run (
1608
+ getOptions (),
1609
+ retryAlgorithmManager .getFor (req ),
1610
+ () -> storageClient .getBucketCallable ().call (req , grpcCallContext ),
1611
+ Decoder .identity ());
1612
+ }
1613
+
1506
1614
private com .google .storage .v2 .Bucket updateBucket (UpdateBucketRequest req ) {
1507
1615
GrpcCallContext grpcCallContext = GrpcCallContext .createDefault ();
1508
1616
return Retrying .run (
@@ -1512,7 +1620,7 @@ private com.google.storage.v2.Bucket updateBucket(UpdateBucketRequest req) {
1512
1620
Decoder .identity ());
1513
1621
}
1514
1622
1515
- private static UpdateBucketRequest createUpdateRequest (
1623
+ private static UpdateBucketRequest createUpdateDefaultAclRequest (
1516
1624
String bucket , ImmutableList <ObjectAccessControl > newDefaultAcls , long metageneration ) {
1517
1625
com .google .storage .v2 .Bucket update =
1518
1626
com .google .storage .v2 .Bucket .newBuilder ()
@@ -1528,4 +1636,21 @@ private static UpdateBucketRequest createUpdateRequest(
1528
1636
.setBucket (update )
1529
1637
.build ();
1530
1638
}
1639
+
1640
+ private static UpdateBucketRequest createUpdateAclRequest (
1641
+ String bucket , ImmutableList <BucketAccessControl > newDefaultAcls , long metageneration ) {
1642
+ com .google .storage .v2 .Bucket update =
1643
+ com .google .storage .v2 .Bucket .newBuilder ()
1644
+ .setName (bucketNameCodec .encode (bucket ))
1645
+ .addAllAcl (newDefaultAcls )
1646
+ .build ();
1647
+ Opts <BucketTargetOpt > opts =
1648
+ Opts .from (
1649
+ UnifiedOpts .fields (ImmutableSet .of (BucketField .ACL )),
1650
+ UnifiedOpts .metagenerationMatch (metageneration ));
1651
+ return opts .updateBucketsRequest ()
1652
+ .apply (UpdateBucketRequest .newBuilder ())
1653
+ .setBucket (update )
1654
+ .build ();
1655
+ }
1531
1656
}
0 commit comments