@@ -904,7 +904,7 @@ public boolean deleteAcl(String bucket, Entity entity, BucketSourceOption... opt
904904 }
905905 long metageneration = resp .getMetageneration ();
906906
907- UpdateBucketRequest req = createUpdateAclRequest (bucket , newAcls , metageneration );
907+ UpdateBucketRequest req = createUpdateBucketAclRequest (bucket , newAcls , metageneration );
908908
909909 com .google .storage .v2 .Bucket updateResult = updateBucket (req );
910910 // read the response to ensure there is no longer an acl for the specified entity
@@ -954,7 +954,7 @@ public Acl updateAcl(String bucket, Acl acl, BucketSourceOption... options) {
954954 .collect (ImmutableList .toImmutableList ());
955955
956956 UpdateBucketRequest req =
957- createUpdateAclRequest (bucket , newDefaultAcls , resp .getMetageneration ());
957+ createUpdateBucketAclRequest (bucket , newDefaultAcls , resp .getMetageneration ());
958958
959959 com .google .storage .v2 .Bucket updateResult = updateBucket (req );
960960
@@ -1109,27 +1109,117 @@ public List<Acl> listDefaultAcls(String bucket) {
11091109
11101110 @ Override
11111111 public Acl getAcl (BlobId blob , Entity entity ) {
1112- return throwNotYetImplemented (fmtMethodName ("getAcl" , BlobId .class , Entity .class ));
1112+ try {
1113+ Object req = codecs .blobId ().encode (blob );
1114+ Object resp = getObjectWithAcls (req );
1115+
1116+ Predicate <ObjectAccessControl > entityPredicate =
1117+ objectAclEntityOrAltEq (codecs .entity ().encode (entity ));
1118+
1119+ Optional <ObjectAccessControl > first =
1120+ resp .getAclList ().stream ().filter (entityPredicate ).findFirst ();
1121+
1122+ // HttpStorageRpc defaults to null if Not Found
1123+ return first .map (codecs .objectAcl ()::decode ).orElse (null );
1124+ } catch (NotFoundException e ) {
1125+ return null ;
1126+ } catch (StorageException se ) {
1127+ if (se .getCode () == 404 ) {
1128+ return null ;
1129+ } else {
1130+ throw se ;
1131+ }
1132+ }
11131133 }
11141134
11151135 @ Override
11161136 public boolean deleteAcl (BlobId blob , Entity entity ) {
1117- return throwNotYetImplemented (fmtMethodName ("deleteAcl" , BlobId .class , Entity .class ));
1137+ try {
1138+ Object obj = codecs .blobId ().encode (blob );
1139+ Object resp = getObjectWithAcls (obj );
1140+ String encode = codecs .entity ().encode (entity );
1141+
1142+ Predicate <ObjectAccessControl > entityPredicate = objectAclEntityOrAltEq (encode );
1143+
1144+ List <ObjectAccessControl > currentDefaultAcls = resp .getAclList ();
1145+ ImmutableList <ObjectAccessControl > newDefaultAcls =
1146+ currentDefaultAcls .stream ()
1147+ .filter (entityPredicate .negate ())
1148+ .collect (ImmutableList .toImmutableList ());
1149+ if (newDefaultAcls .equals (currentDefaultAcls )) {
1150+ // we didn't actually filter anything out, no need to send an RPC, simply return false
1151+ return false ;
1152+ }
1153+ long metageneration = resp .getMetageneration ();
1154+
1155+ UpdateObjectRequest req = createUpdateObjectAclRequest (obj , newDefaultAcls , metageneration );
1156+
1157+ Object updateResult = updateObject (req );
1158+ // read the response to ensure there is no longer an acl for the specified entity
1159+ Optional <ObjectAccessControl > first =
1160+ updateResult .getAclList ().stream ().filter (entityPredicate ).findFirst ();
1161+ return !first .isPresent ();
1162+ } catch (NotFoundException e ) {
1163+ // HttpStorageRpc returns false if the bucket doesn't exist :(
1164+ return false ;
1165+ } catch (StorageException se ) {
1166+ if (se .getCode () == 404 ) {
1167+ return false ;
1168+ } else {
1169+ throw se ;
1170+ }
1171+ }
11181172 }
11191173
11201174 @ Override
11211175 public Acl createAcl (BlobId blob , Acl acl ) {
1122- return throwNotYetImplemented ( fmtMethodName ( "createAcl" , BlobId . class , Acl . class ) );
1176+ return updateAcl ( blob , acl );
11231177 }
11241178
11251179 @ Override
11261180 public Acl updateAcl (BlobId blob , Acl acl ) {
1127- return throwNotYetImplemented (fmtMethodName ("updateAcl" , BlobId .class , Acl .class ));
1181+ try {
1182+ Object obj = codecs .blobId ().encode (blob );
1183+ Object resp = getObjectWithAcls (obj );
1184+ ObjectAccessControl encode = codecs .objectAcl ().encode (acl );
1185+ String entity = encode .getEntity ();
1186+
1187+ Predicate <ObjectAccessControl > entityPredicate = objectAclEntityOrAltEq (entity );
1188+
1189+ ImmutableList <ObjectAccessControl > newDefaultAcls =
1190+ Streams .concat (
1191+ resp .getAclList ().stream ().filter (entityPredicate .negate ()), Stream .of (encode ))
1192+ .collect (ImmutableList .toImmutableList ());
1193+
1194+ UpdateObjectRequest req =
1195+ createUpdateObjectAclRequest (obj , newDefaultAcls , resp .getMetageneration ());
1196+
1197+ Object updateResult = updateObject (req );
1198+
1199+ Optional <Acl > first =
1200+ updateResult .getAclList ().stream ()
1201+ .filter (entityPredicate )
1202+ .findFirst ()
1203+ .map (codecs .objectAcl ()::decode );
1204+
1205+ return first .orElseThrow (
1206+ () -> new StorageException (0 , "Acl update call success, but not in response" ));
1207+ } catch (NotFoundException e ) {
1208+ throw StorageException .coalesce (e );
1209+ }
11281210 }
11291211
11301212 @ Override
11311213 public List <Acl > listAcls (BlobId blob ) {
1132- return throwNotYetImplemented (fmtMethodName ("listAcls" , BlobId .class ));
1214+ try {
1215+ Object req = codecs .blobId ().encode (blob );
1216+ Object resp = getObjectWithAcls (req );
1217+ return resp .getAclList ().stream ()
1218+ .map (codecs .objectAcl ()::decode )
1219+ .collect (ImmutableList .toImmutableList ());
1220+ } catch (NotFoundException e ) {
1221+ throw StorageException .coalesce (e );
1222+ }
11331223 }
11341224
11351225 @ Override
@@ -1637,7 +1727,7 @@ private static UpdateBucketRequest createUpdateDefaultAclRequest(
16371727 .build ();
16381728 }
16391729
1640- private static UpdateBucketRequest createUpdateAclRequest (
1730+ private static UpdateBucketRequest createUpdateBucketAclRequest (
16411731 String bucket , ImmutableList <BucketAccessControl > newDefaultAcls , long metageneration ) {
16421732 com .google .storage .v2 .Bucket update =
16431733 com .google .storage .v2 .Bucket .newBuilder ()
@@ -1653,4 +1743,50 @@ private static UpdateBucketRequest createUpdateAclRequest(
16531743 .setBucket (update )
16541744 .build ();
16551745 }
1746+
1747+ private Object getObjectWithAcls (Object obj ) {
1748+ Fields fields =
1749+ UnifiedOpts .fields (ImmutableSet .of (BucketField .ACL , BucketField .METAGENERATION ));
1750+ GrpcCallContext grpcCallContext = GrpcCallContext .createDefault ();
1751+ GetObjectRequest req =
1752+ fields
1753+ .getObject ()
1754+ .apply (GetObjectRequest .newBuilder ())
1755+ .setBucket (obj .getBucket ())
1756+ .setObject (obj .getName ())
1757+ .build ();
1758+
1759+ return Retrying .run (
1760+ getOptions (),
1761+ retryAlgorithmManager .getFor (req ),
1762+ () -> storageClient .getObjectCallable ().call (req , grpcCallContext ),
1763+ Decoder .identity ());
1764+ }
1765+
1766+ private static UpdateObjectRequest createUpdateObjectAclRequest (
1767+ Object obj , ImmutableList <ObjectAccessControl > newAcls , long metageneration ) {
1768+ Object update =
1769+ Object .newBuilder ()
1770+ .setBucket (obj .getBucket ())
1771+ .setName (obj .getName ())
1772+ .addAllAcl (newAcls )
1773+ .build ();
1774+ Opts <BucketTargetOpt > opts =
1775+ Opts .from (
1776+ UnifiedOpts .fields (ImmutableSet .of (BlobField .ACL )),
1777+ UnifiedOpts .metagenerationMatch (metageneration ));
1778+ return opts .updateObjectsRequest ()
1779+ .apply (UpdateObjectRequest .newBuilder ())
1780+ .setObject (update )
1781+ .build ();
1782+ }
1783+
1784+ private Object updateObject (UpdateObjectRequest req ) {
1785+ GrpcCallContext grpcCallContext = GrpcCallContext .createDefault ();
1786+ return Retrying .run (
1787+ getOptions (),
1788+ retryAlgorithmManager .getFor (req ),
1789+ () -> storageClient .updateObjectCallable ().call (req , grpcCallContext ),
1790+ Decoder .identity ());
1791+ }
16561792}
0 commit comments