1616
1717package com .google .gcloud .storage ;
1818
19+ import static com .google .common .base .MoreObjects .firstNonNull ;
1920import static com .google .common .base .Preconditions .checkArgument ;
2021import static com .google .gcloud .RetryHelper .runWithRetries ;
2122import static com .google .gcloud .spi .StorageRpc .Option .DELIMITER ;
3233import com .google .api .services .storage .model .StorageObject ;
3334import com .google .common .base .Function ;
3435import com .google .common .base .Functions ;
35- import com .google .common .base .MoreObjects ;
3636import com .google .common .collect .ImmutableMap ;
3737import com .google .common .collect .Iterables ;
3838import com .google .common .collect .Lists ;
3939import com .google .common .collect .Maps ;
40+ import com .google .common .collect .Sets ;
41+ import com .google .common .primitives .Ints ;
4042import com .google .gcloud .BaseService ;
4143import com .google .gcloud .ExceptionHandler ;
4244import com .google .gcloud .ExceptionHandler .Interceptor ;
5254import java .util .Arrays ;
5355import java .util .List ;
5456import java .util .Map ;
57+ import java .util .Set ;
5558import java .util .concurrent .Callable ;
5659
5760final class StorageServiceImpl extends BaseService <StorageServiceOptions > implements StorageService {
@@ -76,14 +79,15 @@ public RetryResult beforeEval(Exception exception) {
7679 };
7780 private static final ExceptionHandler EXCEPTION_HANDLER = ExceptionHandler .builder ()
7881 .abortOn (RuntimeException .class ).interceptor (EXCEPTION_HANDLER_INTERCEPTOR ).build ();
82+ private static final byte [] EMPTY_BYTE_ARRAY = {};
7983
8084 private final StorageRpc storageRpc ;
8185 private final RetryParams retryParams ;
8286
8387 StorageServiceImpl (StorageServiceOptions options ) {
8488 super (options );
8589 storageRpc = options .storageRpc ();
86- retryParams = MoreObjects . firstNonNull (options .retryParams (), RetryParams .noRetries ());
90+ retryParams = firstNonNull (options .retryParams (), RetryParams .noRetries ());
8791 // todo: replace nulls with Value.asNull (per toPb)
8892 // todo: configure timeouts - https://developers.google.com/api-client-library/java/google-api-java-client/errors
8993 // todo: provide rewrite - https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite
@@ -111,7 +115,7 @@ public Blob create(Blob blob, final byte[] content, BlobTargetOption... options)
111115 return Blob .fromPb (runWithRetries (new Callable <StorageObject >() {
112116 @ Override
113117 public StorageObject call () {
114- return storageRpc .create (blobPb , content , optionsMap );
118+ return storageRpc .create (blobPb , firstNonNull ( content , EMPTY_BYTE_ARRAY ) , optionsMap );
115119 }
116120 }, retryParams , EXCEPTION_HANDLER ));
117121 }
@@ -120,25 +124,41 @@ public StorageObject call() {
120124 public Bucket get (String bucket , BucketSourceOption ... options ) {
121125 final com .google .api .services .storage .model .Bucket bucketPb = Bucket .of (bucket ).toPb ();
122126 final Map <StorageRpc .Option , ?> optionsMap = optionMap (options );
123- return Bucket . fromPb ( runWithRetries (
127+ com . google . api . services . storage . model . Bucket answer = runWithRetries (
124128 new Callable <com .google .api .services .storage .model .Bucket >() {
125129 @ Override
126130 public com .google .api .services .storage .model .Bucket call () {
127- return storageRpc .get (bucketPb , optionsMap );
131+ try {
132+ return storageRpc .get (bucketPb , optionsMap );
133+ } catch (StorageServiceException ex ) {
134+ if (ex .code () == 404 ) {
135+ return null ;
136+ }
137+ throw ex ;
138+ }
128139 }
129- }, retryParams , EXCEPTION_HANDLER ));
140+ }, retryParams , EXCEPTION_HANDLER );
141+ return answer == null ? null : Bucket .fromPb (answer );
130142 }
131143
132144 @ Override
133145 public Blob get (String bucket , String blob , BlobSourceOption ... options ) {
134146 final StorageObject storedObject = Blob .of (bucket , blob ).toPb ();
135147 final Map <StorageRpc .Option , ?> optionsMap = optionMap (options );
136- return Blob . fromPb ( runWithRetries (new Callable <StorageObject >() {
148+ StorageObject storageObject = runWithRetries (new Callable <StorageObject >() {
137149 @ Override
138150 public StorageObject call () {
139- return storageRpc .get (storedObject , optionsMap );
151+ try {
152+ return storageRpc .get (storedObject , optionsMap );
153+ } catch (StorageServiceException ex ) {
154+ if (ex .code () == 404 ) {
155+ return null ;
156+ }
157+ throw ex ;
158+ }
140159 }
141- }, retryParams , EXCEPTION_HANDLER ));
160+ }, retryParams , EXCEPTION_HANDLER );
161+ return storageObject == null ? null : Blob .fromPb (storageObject );
142162 }
143163
144164 @ Override
@@ -308,20 +328,28 @@ public BatchResponse apply(BatchRequest batchRequest) {
308328 List <BatchResponse .Result <Blob >> updates = transformBatchResult (
309329 toUpdate , response .updates , Blob .FROM_PB_FUNCTION );
310330 List <BatchResponse .Result <Blob >> gets = transformBatchResult (
311- toGet , response .gets , Blob .FROM_PB_FUNCTION );
331+ toGet , response .gets , Blob .FROM_PB_FUNCTION , 404 );
312332 return new BatchResponse (deletes , updates , gets );
313333 }
314334
315335 private <I , O extends Serializable > List <BatchResponse .Result <O >> transformBatchResult (
316336 Iterable <Tuple <StorageObject , Map <StorageRpc .Option , ?>>> request ,
317- Map <StorageObject , Tuple <I , StorageServiceException >> results , Function <I , O > transform ) {
337+ Map <StorageObject , Tuple <I , StorageServiceException >> results , Function <I , O > transform ,
338+ int ... nullOnErrorCodes ) {
339+ Set nullOnErrorCodesSet = Sets .newHashSet (Ints .asList (nullOnErrorCodes ));
318340 List <BatchResponse .Result <O >> response = Lists .newArrayListWithCapacity (results .size ());
319341 for (Tuple <StorageObject , ?> tuple : request ) {
320342 Tuple <I , StorageServiceException > result = results .get (tuple .x ());
321343 if (result .x () != null ) {
322344 response .add (new BatchResponse .Result <>(transform .apply (result .x ())));
323345 } else {
324- response .add (new BatchResponse .Result <O >(result .y ()));
346+ StorageServiceException exception = result .y ();
347+ if (nullOnErrorCodesSet .contains (exception .code ())) {
348+ //noinspection unchecked
349+ response .add (BatchResponse .Result .<O >empty ());
350+ } else {
351+ response .add (new BatchResponse .Result <O >(result .y ()));
352+ }
325353 }
326354 }
327355 return response ;
@@ -368,7 +396,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
368396
369397 private void initTransients () {
370398 storageRpc = serviceOptions .storageRpc ();
371- retryParams = MoreObjects . firstNonNull (serviceOptions .retryParams (), RetryParams .noRetries ());
399+ retryParams = firstNonNull (serviceOptions .retryParams (), RetryParams .noRetries ());
372400 storageObject = blob .toPb ();
373401 }
374402
@@ -504,7 +532,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
504532
505533 private void initTransients () {
506534 storageRpc = options .storageRpc ();
507- retryParams = MoreObjects . firstNonNull (options .retryParams (), RetryParams .noRetries ());
535+ retryParams = firstNonNull (options .retryParams (), RetryParams .noRetries ());
508536 storageObject = blob .toPb ();
509537 }
510538
@@ -600,7 +628,7 @@ private static <T> void addToOptionMap(StorageRpc.Option getOption, StorageRpc.O
600628 T value = (T ) map .remove (getOption );
601629 checkArgument (value != null || defaultValue != null ,
602630 "Option " + getOption .value () + " is missing a value" );
603- value = MoreObjects . firstNonNull (value , defaultValue );
631+ value = firstNonNull (value , defaultValue );
604632 map .put (putOption , value );
605633 }
606634 }
0 commit comments