Skip to content

Commit 76776e3

Browse files
committed
Merge pull request #53 from aozarov/master
complete package-info and make get return null on 404
2 parents 72bb3ee + 9761b3c commit 76776e3

6 files changed

Lines changed: 84 additions & 26 deletions

File tree

src/main/java/com/google/gcloud/examples/StorageExample.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private static abstract class StorageAction<T> {
6969

7070
abstract void run(StorageService storage, T request) throws Exception;
7171

72-
abstract T parse(String... args) throws IllegalArgumentException;
72+
abstract T parse(String... args) throws IllegalArgumentException, IOException;
7373

7474
protected String params() {
7575
return "";
@@ -115,6 +115,8 @@ public String params() {
115115
private static class InfoAction extends BlobsAction {
116116
@Override
117117
public void run(StorageService storage, Blob... blobs) {
118+
119+
118120
if (blobs.length == 1) {
119121
if (blobs[0].name().isEmpty()) {
120122
System.out.println(storage.get(blobs[0].bucket()));
@@ -217,13 +219,14 @@ public void run(StorageService storage, Tuple<Path, Blob> tuple) throws Exceptio
217219
}
218220

219221
@Override
220-
Tuple<Path, Blob> parse(String... args) {
222+
Tuple<Path, Blob> parse(String... args) throws IOException {
221223
if (args.length < 2 || args.length > 3) {
222224
throw new IllegalArgumentException();
223225
}
224226
Path path = Paths.get(args[0]);
227+
String contentType = Files.probeContentType(path);
225228
String blob = args.length < 3 ? path.getFileName().toString() : args[2];
226-
return Tuple.of(path, Blob.of(args[1], blob));
229+
return Tuple.of(path, Blob.builder(args[1], blob).contentType(contentType).build());
227230
}
228231

229232
@Override

src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/main/java/com/google/gcloud/storage/BatchResponse.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ public class BatchResponse implements Serializable {
3636
public static class Result<T extends Serializable> implements Serializable {
3737

3838
private static final long serialVersionUID = -1946539570170529094L;
39+
private static final Result EMPTY = new BatchResponse.Result(null);
3940

4041
private final T value;
4142
private final StorageServiceException exception;
4243

44+
4345
Result(T value) {
4446
this.value = value;
4547
this.exception = null;
@@ -50,13 +52,15 @@ public static class Result<T extends Serializable> implements Serializable {
5052
this.value = null;
5153
}
5254

53-
5455
/**
5556
* Returns the result.
5657
*
5758
* @throws StorageServiceException if failed
5859
*/
5960
public T result() throws StorageServiceException {
61+
if (failed()) {
62+
throw failure();
63+
}
6064
return value;
6165
}
6266

@@ -76,7 +80,15 @@ public boolean failed() {
7680

7781
@Override
7882
public String toString() {
79-
return MoreObjects.firstNonNull(value, exception).toString();
83+
return MoreObjects.toStringHelper(this)
84+
.add("value", value)
85+
.add("exception", exception)
86+
.toString();
87+
}
88+
89+
@SuppressWarnings("unchecked")
90+
static <T extends Serializable> Result<T> empty() {
91+
return EMPTY;
8092
}
8193
}
8294

src/main/java/com/google/gcloud/storage/StorageService.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ public static ComposeRequest of(Iterable<String> sources, Blob target) {
306306
return builder().target(target).addSource(sources).build();
307307
}
308308

309+
public static ComposeRequest of(String bucket, Iterable<String> sources, String target) {
310+
return of(sources, Blob.of(bucket, target));
311+
}
312+
309313
public static Builder builder() {
310314
return new Builder();
311315
}
@@ -390,6 +394,10 @@ public static CopyRequest of(String sourceBucket, String sourceBlob, Blob target
390394
return builder().source(sourceBucket, sourceBlob).target(target).build();
391395
}
392396

397+
public static CopyRequest of(String sourceBucket, String sourceBlob, String targetBlob) {
398+
return of(sourceBucket, sourceBlob, Blob.of(sourceBucket, targetBlob));
399+
}
400+
393401
public static Builder builder() {
394402
return new Builder();
395403
}
@@ -412,14 +420,14 @@ public static Builder builder() {
412420
Blob create(Blob blob, byte[] content, BlobTargetOption... options);
413421

414422
/**
415-
* Return the requested bucket.
423+
* Return the requested bucket or {@code null} if not found.
416424
*
417425
* @throws StorageServiceException upon failure
418426
*/
419427
Bucket get(String bucket, BucketSourceOption... options);
420428

421429
/**
422-
* Return the requested blob.
430+
* Return the requested blob or {@code null} if not found.
423431
*
424432
* @throws StorageServiceException upon failure
425433
*/
@@ -516,5 +524,4 @@ public static Builder builder() {
516524
* @throws StorageServiceException upon failure
517525
*/
518526
BlobWriteChannel writer(Blob blob, BlobTargetOption... options);
519-
520527
}

src/main/java/com/google/gcloud/storage/StorageServiceImpl.java

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.gcloud.storage;
1818

19+
import static com.google.common.base.MoreObjects.firstNonNull;
1920
import static com.google.common.base.Preconditions.checkArgument;
2021
import static com.google.gcloud.RetryHelper.runWithRetries;
2122
import static com.google.gcloud.spi.StorageRpc.Option.DELIMITER;
@@ -32,11 +33,12 @@
3233
import com.google.api.services.storage.model.StorageObject;
3334
import com.google.common.base.Function;
3435
import com.google.common.base.Functions;
35-
import com.google.common.base.MoreObjects;
3636
import com.google.common.collect.ImmutableMap;
3737
import com.google.common.collect.Iterables;
3838
import com.google.common.collect.Lists;
3939
import com.google.common.collect.Maps;
40+
import com.google.common.collect.Sets;
41+
import com.google.common.primitives.Ints;
4042
import com.google.gcloud.BaseService;
4143
import com.google.gcloud.ExceptionHandler;
4244
import com.google.gcloud.ExceptionHandler.Interceptor;
@@ -52,6 +54,7 @@
5254
import java.util.Arrays;
5355
import java.util.List;
5456
import java.util.Map;
57+
import java.util.Set;
5558
import java.util.concurrent.Callable;
5659

5760
final 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
}

src/main/java/com/google/gcloud/storage/package-info.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,16 @@
2222
* StorageServiceOptions options = StorageServiceOptions.builder().projectId("project").build();
2323
* StorageService storage = StorageServiceFactory.instance().get(options);
2424
* byte[] content = readContent();
25-
* Blob blob = storage.create(Blob.of("bucket", "blob_name"), content);
26-
* } </pre>
25+
* Blob blob = storage.get("bucket", "blob_name");
26+
* if (blob == null) {
27+
* storage.create(Blob.of("bucket", "blob_name"), content);
28+
* } else {
29+
* byte[] prevContent = storage.load("bucket", "blob_name");
30+
* content = mergeContent(prevContent, content);
31+
* WritableByteChannel channel = storage.writer(blob);
32+
* channel.write(ByteBuffer.wrap(content));
33+
* channel.close();
34+
* }}</pre>
2735
*
2836
* @see <a href="https://cloud.google.com/storage/">Google Cloud Storage</a>
2937
*/

0 commit comments

Comments
 (0)