Skip to content

Commit

Permalink
Merge pull request #53 from aozarov/master
Browse files Browse the repository at this point in the history
complete package-info and make get return null on 404
  • Loading branch information
aozarov committed May 12, 2015
2 parents 72bb3ee + 9761b3c commit 76776e3
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 26 deletions.
9 changes: 6 additions & 3 deletions src/main/java/com/google/gcloud/examples/StorageExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private static abstract class StorageAction<T> {

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

abstract T parse(String... args) throws IllegalArgumentException;
abstract T parse(String... args) throws IllegalArgumentException, IOException;

protected String params() {
return "";
Expand Down Expand Up @@ -115,6 +115,8 @@ public String params() {
private static class InfoAction extends BlobsAction {
@Override
public void run(StorageService storage, Blob... blobs) {


if (blobs.length == 1) {
if (blobs[0].name().isEmpty()) {
System.out.println(storage.get(blobs[0].bucket()));
Expand Down Expand Up @@ -217,13 +219,14 @@ public void run(StorageService storage, Tuple<Path, Blob> tuple) throws Exceptio
}

@Override
Tuple<Path, Blob> parse(String... args) {
Tuple<Path, Blob> parse(String... args) throws IOException {
if (args.length < 2 || args.length > 3) {
throw new IllegalArgumentException();
}
Path path = Paths.get(args[0]);
String contentType = Files.probeContentType(path);
String blob = args.length < 3 ? path.getFileName().toString() : args[2];
return Tuple.of(path, Blob.of(args[1], blob));
return Tuple.of(path, Blob.builder(args[1], blob).contentType(contentType).build());
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions src/main/java/com/google/gcloud/storage/BatchResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ public class BatchResponse implements Serializable {
public static class Result<T extends Serializable> implements Serializable {

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

private final T value;
private final StorageServiceException exception;


Result(T value) {
this.value = value;
this.exception = null;
Expand All @@ -50,13 +52,15 @@ public static class Result<T extends Serializable> implements Serializable {
this.value = null;
}


/**
* Returns the result.
*
* @throws StorageServiceException if failed
*/
public T result() throws StorageServiceException {
if (failed()) {
throw failure();
}
return value;
}

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

@Override
public String toString() {
return MoreObjects.firstNonNull(value, exception).toString();
return MoreObjects.toStringHelper(this)
.add("value", value)
.add("exception", exception)
.toString();
}

@SuppressWarnings("unchecked")
static <T extends Serializable> Result<T> empty() {
return EMPTY;
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/main/java/com/google/gcloud/storage/StorageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ public static ComposeRequest of(Iterable<String> sources, Blob target) {
return builder().target(target).addSource(sources).build();
}

public static ComposeRequest of(String bucket, Iterable<String> sources, String target) {
return of(sources, Blob.of(bucket, target));
}

public static Builder builder() {
return new Builder();
}
Expand Down Expand Up @@ -390,6 +394,10 @@ public static CopyRequest of(String sourceBucket, String sourceBlob, Blob target
return builder().source(sourceBucket, sourceBlob).target(target).build();
}

public static CopyRequest of(String sourceBucket, String sourceBlob, String targetBlob) {
return of(sourceBucket, sourceBlob, Blob.of(sourceBucket, targetBlob));
}

public static Builder builder() {
return new Builder();
}
Expand All @@ -412,14 +420,14 @@ public static Builder builder() {
Blob create(Blob blob, byte[] content, BlobTargetOption... options);

/**
* Return the requested bucket.
* Return the requested bucket or {@code null} if not found.
*
* @throws StorageServiceException upon failure
*/
Bucket get(String bucket, BucketSourceOption... options);

/**
* Return the requested blob.
* Return the requested blob or {@code null} if not found.
*
* @throws StorageServiceException upon failure
*/
Expand Down Expand Up @@ -516,5 +524,4 @@ public static Builder builder() {
* @throws StorageServiceException upon failure
*/
BlobWriteChannel writer(Blob blob, BlobTargetOption... options);

}
58 changes: 43 additions & 15 deletions src/main/java/com/google/gcloud/storage/StorageServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.gcloud.storage;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.gcloud.RetryHelper.runWithRetries;
import static com.google.gcloud.spi.StorageRpc.Option.DELIMITER;
Expand All @@ -32,11 +33,12 @@
import com.google.api.services.storage.model.StorageObject;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import com.google.gcloud.BaseService;
import com.google.gcloud.ExceptionHandler;
import com.google.gcloud.ExceptionHandler.Interceptor;
Expand All @@ -52,6 +54,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

final class StorageServiceImpl extends BaseService<StorageServiceOptions> implements StorageService {
Expand All @@ -76,14 +79,15 @@ public RetryResult beforeEval(Exception exception) {
};
private static final ExceptionHandler EXCEPTION_HANDLER = ExceptionHandler.builder()
.abortOn(RuntimeException.class).interceptor(EXCEPTION_HANDLER_INTERCEPTOR).build();
private static final byte[] EMPTY_BYTE_ARRAY = {};

private final StorageRpc storageRpc;
private final RetryParams retryParams;

StorageServiceImpl(StorageServiceOptions options) {
super(options);
storageRpc = options.storageRpc();
retryParams = MoreObjects.firstNonNull(options.retryParams(), RetryParams.noRetries());
retryParams = firstNonNull(options.retryParams(), RetryParams.noRetries());
// todo: replace nulls with Value.asNull (per toPb)
// todo: configure timeouts - https://developers.google.com/api-client-library/java/google-api-java-client/errors
// todo: provide rewrite - https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite
Expand Down Expand Up @@ -111,7 +115,7 @@ public Blob create(Blob blob, final byte[] content, BlobTargetOption... options)
return Blob.fromPb(runWithRetries(new Callable<StorageObject>() {
@Override
public StorageObject call() {
return storageRpc.create(blobPb, content, optionsMap);
return storageRpc.create(blobPb, firstNonNull(content, EMPTY_BYTE_ARRAY), optionsMap);
}
}, retryParams, EXCEPTION_HANDLER));
}
Expand All @@ -120,25 +124,41 @@ public StorageObject call() {
public Bucket get(String bucket, BucketSourceOption... options) {
final com.google.api.services.storage.model.Bucket bucketPb = Bucket.of(bucket).toPb();
final Map<StorageRpc.Option, ?> optionsMap = optionMap(options);
return Bucket.fromPb(runWithRetries(
com.google.api.services.storage.model.Bucket answer = runWithRetries(
new Callable<com.google.api.services.storage.model.Bucket>() {
@Override
public com.google.api.services.storage.model.Bucket call() {
return storageRpc.get(bucketPb, optionsMap);
try {
return storageRpc.get(bucketPb, optionsMap);
} catch (StorageServiceException ex) {
if (ex.code() == 404) {
return null;
}
throw ex;
}
}
}, retryParams, EXCEPTION_HANDLER));
}, retryParams, EXCEPTION_HANDLER);
return answer == null ? null : Bucket.fromPb(answer);
}

@Override
public Blob get(String bucket, String blob, BlobSourceOption... options) {
final StorageObject storedObject = Blob.of(bucket, blob).toPb();
final Map<StorageRpc.Option, ?> optionsMap = optionMap(options);
return Blob.fromPb(runWithRetries(new Callable<StorageObject>() {
StorageObject storageObject = runWithRetries(new Callable<StorageObject>() {
@Override
public StorageObject call() {
return storageRpc.get(storedObject, optionsMap);
try {
return storageRpc.get(storedObject, optionsMap);
} catch (StorageServiceException ex) {
if (ex.code() == 404) {
return null;
}
throw ex;
}
}
}, retryParams, EXCEPTION_HANDLER));
}, retryParams, EXCEPTION_HANDLER);
return storageObject == null ? null : Blob.fromPb(storageObject);
}

@Override
Expand Down Expand Up @@ -308,20 +328,28 @@ public BatchResponse apply(BatchRequest batchRequest) {
List<BatchResponse.Result<Blob>> updates = transformBatchResult(
toUpdate, response.updates, Blob.FROM_PB_FUNCTION);
List<BatchResponse.Result<Blob>> gets = transformBatchResult(
toGet, response.gets, Blob.FROM_PB_FUNCTION);
toGet, response.gets, Blob.FROM_PB_FUNCTION, 404);
return new BatchResponse(deletes, updates, gets);
}

private <I, O extends Serializable> List<BatchResponse.Result<O>> transformBatchResult(
Iterable<Tuple<StorageObject, Map<StorageRpc.Option, ?>>> request,
Map<StorageObject, Tuple<I, StorageServiceException>> results, Function<I, O> transform) {
Map<StorageObject, Tuple<I, StorageServiceException>> results, Function<I, O> transform,
int... nullOnErrorCodes) {
Set nullOnErrorCodesSet = Sets.newHashSet(Ints.asList(nullOnErrorCodes));
List<BatchResponse.Result<O>> response = Lists.newArrayListWithCapacity(results.size());
for (Tuple<StorageObject, ?> tuple : request) {
Tuple<I, StorageServiceException> result = results.get(tuple.x());
if (result.x() != null) {
response.add(new BatchResponse.Result<>(transform.apply(result.x())));
} else {
response.add(new BatchResponse.Result<O>(result.y()));
StorageServiceException exception = result.y();
if (nullOnErrorCodesSet.contains(exception.code())) {
//noinspection unchecked
response.add(BatchResponse.Result.<O>empty());
} else {
response.add(new BatchResponse.Result<O>(result.y()));
}
}
}
return response;
Expand Down Expand Up @@ -368,7 +396,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE

private void initTransients() {
storageRpc = serviceOptions.storageRpc();
retryParams = MoreObjects.firstNonNull(serviceOptions.retryParams(), RetryParams.noRetries());
retryParams = firstNonNull(serviceOptions.retryParams(), RetryParams.noRetries());
storageObject = blob.toPb();
}

Expand Down Expand Up @@ -504,7 +532,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE

private void initTransients() {
storageRpc = options.storageRpc();
retryParams = MoreObjects.firstNonNull(options.retryParams(), RetryParams.noRetries());
retryParams = firstNonNull(options.retryParams(), RetryParams.noRetries());
storageObject = blob.toPb();
}

Expand Down Expand Up @@ -600,7 +628,7 @@ private static <T> void addToOptionMap(StorageRpc.Option getOption, StorageRpc.O
T value = (T) map.remove(getOption);
checkArgument(value != null || defaultValue != null,
"Option " + getOption.value() + " is missing a value");
value = MoreObjects.firstNonNull(value, defaultValue);
value = firstNonNull(value, defaultValue);
map.put(putOption, value);
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/main/java/com/google/gcloud/storage/package-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@
* StorageServiceOptions options = StorageServiceOptions.builder().projectId("project").build();
* StorageService storage = StorageServiceFactory.instance().get(options);
* byte[] content = readContent();
* Blob blob = storage.create(Blob.of("bucket", "blob_name"), content);
* } </pre>
* Blob blob = storage.get("bucket", "blob_name");
* if (blob == null) {
* storage.create(Blob.of("bucket", "blob_name"), content);
* } else {
* byte[] prevContent = storage.load("bucket", "blob_name");
* content = mergeContent(prevContent, content);
* WritableByteChannel channel = storage.writer(blob);
* channel.write(ByteBuffer.wrap(content));
* channel.close();
* }}</pre>
*
* @see <a href="https://cloud.google.com/storage/">Google Cloud Storage</a>
*/
Expand Down

0 comments on commit 76776e3

Please sign in to comment.