Skip to content

Commit f4a12e4

Browse files
authored
Add user project options for requester pays flag (#2260)
1 parent 0e4ed46 commit f4a12e4

7 files changed

Lines changed: 153 additions & 15 deletions

File tree

google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static com.google.common.base.Preconditions.checkNotNull;
2323

2424
import com.google.api.gax.paging.Page;
25+
import com.google.cloud.GcpLaunchStage;
2526
import com.google.cloud.Tuple;
2627
import com.google.cloud.storage.Acl.Entity;
2728
import com.google.cloud.storage.Storage.BlobGetOption;
@@ -71,6 +72,10 @@ private BucketSourceOption(StorageRpc.Option rpcOption) {
7172
super(rpcOption, null);
7273
}
7374

75+
private BucketSourceOption(StorageRpc.Option rpcOption, Object value) {
76+
super(rpcOption, value);
77+
}
78+
7479
private Storage.BucketSourceOption toSourceOption(BucketInfo bucketInfo) {
7580
switch (getRpcOption()) {
7681
case IF_METAGENERATION_MATCH:
@@ -109,6 +114,15 @@ public static BucketSourceOption metagenerationNotMatch() {
109114
return new BucketSourceOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH);
110115
}
111116

117+
/**
118+
* Returns an option for blob's billing user project. This option is only used by the buckets with
119+
* 'requester_pays' flag.
120+
*/
121+
@GcpLaunchStage.Alpha
122+
public static BucketSourceOption userProject(String userProject) {
123+
return new BucketSourceOption(StorageRpc.Option.USER_PROJECT, userProject);
124+
}
125+
112126
static Storage.BucketSourceOption[] toSourceOptions(BucketInfo bucketInfo,
113127
BucketSourceOption... options) {
114128
Storage.BucketSourceOption[] convertedOptions =
@@ -174,6 +188,9 @@ private Tuple<BlobInfo, Storage.BlobTargetOption> toTargetOption(BlobInfo blobIn
174188
case CUSTOMER_SUPPLIED_KEY:
175189
return Tuple.of(blobInfo,
176190
Storage.BlobTargetOption.encryptionKey((String) getValue()));
191+
case USER_PROJECT:
192+
return Tuple.of(blobInfo,
193+
Storage.BlobTargetOption.userProject((String) getValue()));
177194
default:
178195
throw new AssertionError("Unexpected enum value");
179196
}
@@ -250,6 +267,15 @@ public static BlobTargetOption encryptionKey(String key) {
250267
return new BlobTargetOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, key);
251268
}
252269

270+
/**
271+
* Returns an option for blob's billing user project. This option is only used by the buckets with
272+
* 'requester_pays' flag.
273+
*/
274+
@GcpLaunchStage.Alpha
275+
public static BlobTargetOption userProject(String userProject) {
276+
return new BlobTargetOption(StorageRpc.Option.USER_PROJECT, userProject);
277+
}
278+
253279
static Tuple<BlobInfo, Storage.BlobTargetOption[]> toTargetOptions(
254280
BlobInfo info, BlobTargetOption... options) {
255281
Set<StorageRpc.Option> optionSet =
@@ -319,6 +345,8 @@ private Tuple<BlobInfo, Storage.BlobWriteOption> toWriteOption(BlobInfo blobInfo
319345
case CUSTOMER_SUPPLIED_KEY:
320346
return Tuple.of(blobInfo,
321347
Storage.BlobWriteOption.encryptionKey((String) value));
348+
case USER_PROJECT:
349+
return Tuple.of(blobInfo, Storage.BlobWriteOption.userProject((String) value));
322350
default:
323351
throw new AssertionError("Unexpected enum value");
324352
}
@@ -436,6 +464,15 @@ public static BlobWriteOption encryptionKey(String key) {
436464
return new BlobWriteOption(Storage.BlobWriteOption.Option.CUSTOMER_SUPPLIED_KEY, key);
437465
}
438466

467+
/**
468+
* Returns an option for blob's billing user project. This option is only used by the buckets with
469+
* 'requester_pays' flag.
470+
*/
471+
@GcpLaunchStage.Alpha
472+
public static BlobWriteOption userProject(String userProject) {
473+
return new BlobWriteOption(Storage.BlobWriteOption.Option.USER_PROJECT, userProject);
474+
}
475+
439476
static Tuple<BlobInfo, Storage.BlobWriteOption[]> toWriteOptions(
440477
BlobInfo info, BlobWriteOption... options) {
441478
Set<Storage.BlobWriteOption.Option> optionSet =

google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ public abstract static class Builder {
342342
/**
343343
* Sets whether a user accessing the bucket or an object it contains should assume the transit costs
344344
* related to the access.
345+
*
346+
* GcpLaunchStage.Alpha
345347
*/
346348
abstract Builder setRequesterPays(Boolean requesterPays);
347349

@@ -503,6 +505,7 @@ public Builder setVersioningEnabled(Boolean enable) {
503505
return this;
504506
}
505507

508+
/** GcpLaunchStage.Alpha */
506509
@Override
507510
public Builder setRequesterPays(Boolean enable) {
508511
this.requesterPays = firstNonNull(enable, Data.<Boolean>nullOf(Boolean.class));
@@ -648,6 +651,8 @@ public Boolean versioningEnabled() {
648651
/**
649652
* Returns {@code true} if a user accessing the bucket or an object it contains should assume the transit costs
650653
* related to the access, {@code false} otherwise.
654+
*
655+
* GcpLaunchStage.Alpha
651656
*/
652657
public Boolean requesterPays() {
653658
return Data.isNull(requesterPays) ? null : requesterPays;

google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ public static BucketTargetOption metagenerationMatch() {
195195
public static BucketTargetOption metagenerationNotMatch() {
196196
return new BucketTargetOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH);
197197
}
198+
199+
/**
200+
* Returns an option for bucket's billing user project. This option is only used by the buckets with
201+
* 'requester_pays' flag.
202+
*/
203+
@GcpLaunchStage.Alpha
204+
public static BucketTargetOption userProject(String userProject) {
205+
return new BucketTargetOption(StorageRpc.Option.USER_PROJECT, userProject);
206+
}
198207
}
199208

200209
/**
@@ -204,8 +213,8 @@ class BucketSourceOption extends Option {
204213

205214
private static final long serialVersionUID = 5185657617120212117L;
206215

207-
private BucketSourceOption(StorageRpc.Option rpcOption, long metageneration) {
208-
super(rpcOption, metageneration);
216+
private BucketSourceOption(StorageRpc.Option rpcOption, Object value) {
217+
super(rpcOption, value);
209218
}
210219

211220
/**
@@ -223,10 +232,19 @@ public static BucketSourceOption metagenerationMatch(long metageneration) {
223232
public static BucketSourceOption metagenerationNotMatch(long metageneration) {
224233
return new BucketSourceOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH, metageneration);
225234
}
235+
236+
/**
237+
* Returns an option for bucket's billing user project. This option is only used by the buckets with
238+
* 'requester_pays' flag.
239+
*/
240+
@GcpLaunchStage.Alpha
241+
public static BucketSourceOption userProject(String userProject) {
242+
return new BucketSourceOption(StorageRpc.Option.USER_PROJECT, userProject);
243+
}
226244
}
227245

228246
/**
229-
* Class for specifying bucket source options.
247+
* Class for specifying bucket get options.
230248
*/
231249
class BucketGetOption extends Option {
232250

@@ -256,6 +274,15 @@ public static BucketGetOption metagenerationNotMatch(long metageneration) {
256274
return new BucketGetOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH, metageneration);
257275
}
258276

277+
/**
278+
* Returns an option for bucket's billing user project. This option is only used by the buckets with
279+
* 'requester_pays' flag.
280+
*/
281+
@GcpLaunchStage.Alpha
282+
public static BucketGetOption userProject(String userProject) {
283+
return new BucketGetOption(StorageRpc.Option.USER_PROJECT, userProject);
284+
}
285+
259286
/**
260287
* Returns an option to specify the bucket's fields to be returned by the RPC call. If this
261288
* option is not provided all bucket's fields are returned. {@code BucketGetOption.fields}) can
@@ -338,6 +365,15 @@ public static BlobTargetOption encryptionKey(Key key) {
338365
return new BlobTargetOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, base64Key);
339366
}
340367

368+
/**
369+
* Returns an option for blob's billing user project. This option is only used by the buckets with
370+
* 'requester_pays' flag.
371+
*/
372+
@GcpLaunchStage.Alpha
373+
public static BlobTargetOption userProject(String userProject) {
374+
return new BlobTargetOption(StorageRpc.Option.USER_PROJECT, userProject);
375+
}
376+
341377
/**
342378
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
343379
* blob.
@@ -381,7 +417,7 @@ class BlobWriteOption implements Serializable {
381417

382418
enum Option {
383419
PREDEFINED_ACL, IF_GENERATION_MATCH, IF_GENERATION_NOT_MATCH, IF_METAGENERATION_MATCH,
384-
IF_METAGENERATION_NOT_MATCH, IF_MD5_MATCH, IF_CRC32C_MATCH, CUSTOMER_SUPPLIED_KEY;
420+
IF_METAGENERATION_NOT_MATCH, IF_MD5_MATCH, IF_CRC32C_MATCH, CUSTOMER_SUPPLIED_KEY, USER_PROJECT;
385421

386422
StorageRpc.Option toRpcOption() {
387423
return StorageRpc.Option.valueOf(this.name());
@@ -498,6 +534,15 @@ public static BlobWriteOption encryptionKey(Key key) {
498534
public static BlobWriteOption encryptionKey(String key) {
499535
return new BlobWriteOption(Option.CUSTOMER_SUPPLIED_KEY, key);
500536
}
537+
538+
/**
539+
* Returns an option for blob's billing user project. This option is only used by the buckets with
540+
* 'requester_pays' flag.
541+
*/
542+
@GcpLaunchStage.Alpha
543+
public static BlobWriteOption userProject(String userProject) {
544+
return new BlobWriteOption(Option.USER_PROJECT, userProject);
545+
}
501546
}
502547

503548
/**
@@ -583,6 +628,15 @@ public static BlobSourceOption decryptionKey(Key key) {
583628
public static BlobSourceOption decryptionKey(String key) {
584629
return new BlobSourceOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, key);
585630
}
631+
632+
/**
633+
* Returns an option for blob's billing user project. This option is only used by the buckets with
634+
* 'requester_pays' flag.
635+
*/
636+
@GcpLaunchStage.Alpha
637+
public static BlobSourceOption userProject(String userProject) {
638+
return new BlobSourceOption(StorageRpc.Option.USER_PROJECT, userProject);
639+
}
586640
}
587641

588642
/**
@@ -664,6 +718,15 @@ public static BlobGetOption fields(BlobField... fields) {
664718
return new BlobGetOption(StorageRpc.Option.FIELDS,
665719
Helper.selector(BlobField.REQUIRED_FIELDS, fields));
666720
}
721+
722+
/**
723+
* Returns an option for blob's billing user project. This option is only used by the buckets with
724+
* 'requester_pays' flag.
725+
*/
726+
@GcpLaunchStage.Alpha
727+
public static BlobGetOption userProject(String userProject) {
728+
return new BlobGetOption(StorageRpc.Option.USER_PROJECT, userProject);
729+
}
667730
}
668731

669732
/**

google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ public StorageObject create(StorageObject storageObject, final InputStream conte
235235
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
236236
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
237237
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
238+
.setUserProject(Option.USER_PROJECT.getString(options))
238239
.execute();
239240
} catch (IOException ex) {
240241
throw translate(ex);
@@ -270,6 +271,7 @@ public Tuple<String, Iterable<StorageObject>> list(final String bucket, Map<Opti
270271
.setMaxResults(Option.MAX_RESULTS.getLong(options))
271272
.setPageToken(Option.PAGE_TOKEN.getString(options))
272273
.setFields(Option.FIELDS.getString(options))
274+
.setUserProject(Option.USER_PROJECT.getString(options))
273275
.execute();
274276
Iterable<StorageObject> storageObjects = Iterables.concat(
275277
firstNonNull(objects.getItems(), ImmutableList.<StorageObject>of()),
@@ -304,6 +306,7 @@ public Bucket get(Bucket bucket, Map<Option, ?> options) {
304306
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
305307
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
306308
.setFields(Option.FIELDS.getString(options))
309+
.setUserProject(Option.USER_PROJECT.getString(options))
307310
.execute();
308311
} catch (IOException ex) {
309312
StorageException serviceException = translate(ex);
@@ -324,7 +327,8 @@ private Storage.Objects.Get getCall(StorageObject object, Map<Option, ?> options
324327
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
325328
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
326329
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
327-
.setFields(Option.FIELDS.getString(options));
330+
.setFields(Option.FIELDS.getString(options))
331+
.setUserProject(Option.USER_PROJECT.getString(options));
328332
}
329333

330334
@Override
@@ -350,6 +354,7 @@ public Bucket patch(Bucket bucket, Map<Option, ?> options) {
350354
.setPredefinedDefaultObjectAcl(Option.PREDEFINED_DEFAULT_OBJECT_ACL.getString(options))
351355
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
352356
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
357+
.setUserProject(Option.USER_PROJECT.getString(options))
353358
.execute();
354359
} catch (IOException ex) {
355360
throw translate(ex);
@@ -365,7 +370,8 @@ private Storage.Objects.Patch patchCall(StorageObject storageObject, Map<Option,
365370
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
366371
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
367372
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
368-
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options));
373+
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
374+
.setUserProject(Option.USER_PROJECT.getString(options));
369375
}
370376

371377
@Override
@@ -384,6 +390,7 @@ public boolean delete(Bucket bucket, Map<Option, ?> options) {
384390
.delete(bucket.getName())
385391
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
386392
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
393+
.setUserProject(Option.USER_PROJECT.getString(options))
387394
.execute();
388395
return true;
389396
} catch (IOException ex) {
@@ -403,7 +410,8 @@ private Storage.Objects.Delete deleteCall(StorageObject blob, Map<Option, ?> opt
403410
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
404411
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
405412
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
406-
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options));
413+
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
414+
.setUserProject(Option.USER_PROJECT.getString(options));
407415
}
408416

409417
@Override
@@ -443,6 +451,7 @@ public StorageObject compose(Iterable<StorageObject> sources, StorageObject targ
443451
.compose(target.getBucket(), target.getName(), request)
444452
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(targetOptions))
445453
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(targetOptions))
454+
.setUserProject(Option.USER_PROJECT.getString(targetOptions))
446455
.execute();
447456
} catch (IOException ex) {
448457
throw translate(ex);
@@ -458,7 +467,8 @@ public byte[] load(StorageObject from, Map<Option, ?> options) {
458467
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
459468
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
460469
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
461-
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options));
470+
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
471+
.setUserProject(Option.USER_PROJECT.getString(options));
462472
setEncryptionHeaders(getRequest.getRequestHeaders(), ENCRYPTION_KEY_PREFIX, options);
463473
ByteArrayOutputStream out = new ByteArrayOutputStream();
464474
getRequest.executeMedia().download(out);
@@ -483,7 +493,8 @@ public Tuple<String, byte[]> read(StorageObject from, Map<Option, ?> options, lo
483493
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(options))
484494
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(options))
485495
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(options))
486-
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options));
496+
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(options))
497+
.setUserProject(Option.USER_PROJECT.getString(options));
487498
checkArgument(position >= 0, "Position should be non-negative, is %d", position);
488499
StringBuilder range = new StringBuilder();
489500
range.append("bytes=").append(position).append("-").append(position + bytes - 1);
@@ -628,6 +639,11 @@ public RewriteResponse continueRewrite(RewriteResponse previousResponse) {
628639

629640
private RewriteResponse rewrite(RewriteRequest req, String token) {
630641
try {
642+
String userProject = Option.USER_PROJECT.getString(req.sourceOptions);
643+
if (userProject == null) {
644+
userProject = Option.USER_PROJECT.getString(req.targetOptions);
645+
}
646+
631647
Long maxBytesRewrittenPerCall = req.megabytesRewrittenPerCall != null
632648
? req.megabytesRewrittenPerCall * MEGABYTE : null;
633649
Storage.Objects.Rewrite rewrite = storage.objects()
@@ -645,7 +661,8 @@ private RewriteResponse rewrite(RewriteRequest req, String token) {
645661
.setIfMetagenerationMatch(Option.IF_METAGENERATION_MATCH.getLong(req.targetOptions))
646662
.setIfMetagenerationNotMatch(Option.IF_METAGENERATION_NOT_MATCH.getLong(req.targetOptions))
647663
.setIfGenerationMatch(Option.IF_GENERATION_MATCH.getLong(req.targetOptions))
648-
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(req.targetOptions));
664+
.setIfGenerationNotMatch(Option.IF_GENERATION_NOT_MATCH.getLong(req.targetOptions))
665+
.setUserProject(userProject);
649666
HttpHeaders requestHeaders = rewrite.getRequestHeaders();
650667
setEncryptionHeaders(requestHeaders, SOURCE_ENCRYPTION_KEY_PREFIX, req.sourceOptions);
651668
setEncryptionHeaders(requestHeaders, ENCRYPTION_KEY_PREFIX, req.targetOptions);

google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ enum Option {
5050
DELIMITER("delimiter"),
5151
VERSIONS("versions"),
5252
FIELDS("fields"),
53-
CUSTOMER_SUPPLIED_KEY("customerSuppliedKey");
53+
CUSTOMER_SUPPLIED_KEY("customerSuppliedKey"),
54+
USER_PROJECT("userProject");
5455

5556
private final String value;
5657

0 commit comments

Comments
 (0)