Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

complete package-info and make get return null on 404 #53

Merged
merged 4 commits into from
May 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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