Skip to content

Commit cedc9a2

Browse files
committed
Merge pull request #233 from mziccard/simple-storage-batch-requests
Add batch get, update, delete methods to Storage and Blob
2 parents 469be5f + f2b6adc commit cedc9a2

9 files changed

Lines changed: 506 additions & 10 deletions

File tree

gcloud-java-storage/src/main/java/com/google/gcloud/spi/StorageRpc.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.gcloud.spi;
1818

19+
import static com.google.common.base.MoreObjects.firstNonNull;
20+
1921
import com.google.api.services.storage.model.Bucket;
2022
import com.google.api.services.storage.model.StorageObject;
2123
import com.google.common.collect.ImmutableList;
@@ -106,9 +108,12 @@ class BatchRequest {
106108
public BatchRequest(Iterable<Tuple<StorageObject, Map<Option, ?>>> toDelete,
107109
Iterable<Tuple<StorageObject, Map<Option, ?>>> toUpdate,
108110
Iterable<Tuple<StorageObject, Map<Option, ?>>> toGet) {
109-
this.toDelete = ImmutableList.copyOf(toDelete);
110-
this.toUpdate = ImmutableList.copyOf(toUpdate);
111-
this.toGet = ImmutableList.copyOf(toGet);
111+
this.toDelete = ImmutableList.copyOf(
112+
firstNonNull(toDelete, ImmutableList.<Tuple<StorageObject, Map<Option, ?>>>of()));
113+
this.toUpdate = ImmutableList.copyOf(
114+
firstNonNull(toUpdate, ImmutableList.<Tuple<StorageObject, Map<Option, ?>>>of()));
115+
this.toGet = ImmutableList.copyOf(
116+
firstNonNull(toGet, ImmutableList.<Tuple<StorageObject, Map<Option, ?>>>of()));
112117
}
113118
}
114119

gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@
2020
import static com.google.common.base.Preconditions.checkNotNull;
2121
import static com.google.gcloud.storage.Blob.BlobSourceOption.convert;
2222

23+
import com.google.common.base.Function;
24+
import com.google.common.collect.Lists;
2325
import com.google.gcloud.spi.StorageRpc;
2426
import com.google.gcloud.storage.Storage.BlobTargetOption;
2527
import com.google.gcloud.storage.Storage.CopyRequest;
2628
import com.google.gcloud.storage.Storage.SignUrlOption;
2729

2830
import java.net.URL;
31+
import java.util.Arrays;
32+
import java.util.Collections;
33+
import java.util.List;
2934
import java.util.Objects;
3035

3136
/**
@@ -256,4 +261,74 @@ public URL signUrl(long expirationTimeInSeconds, SignUrlOption... options) {
256261
public Storage storage() {
257262
return storage;
258263
}
264+
265+
/**
266+
* Gets the requested blobs. If {@code infos.length == 0} an empty list is returned. If
267+
* {@code infos.length > 1} a batch request is used to fetch blobs.
268+
*
269+
* @param storage the storage service used to issue the request
270+
* @param infos the blobs to get
271+
* @return an immutable list of {@code Blob} objects. If a blob does not exist or access to it has
272+
* been denied the corresponding item in the list is {@code null}.
273+
* @throws StorageException upon failure
274+
*/
275+
public static List<Blob> get(final Storage storage, BlobInfo... infos) {
276+
checkNotNull(storage);
277+
checkNotNull(infos);
278+
if (infos.length == 0) {
279+
return Collections.emptyList();
280+
}
281+
return Collections.unmodifiableList(Lists.transform(storage.get(infos),
282+
new Function<BlobInfo, Blob>() {
283+
@Override
284+
public Blob apply(BlobInfo f) {
285+
return f != null ? new Blob(storage, f) : null;
286+
}
287+
}));
288+
}
289+
290+
/**
291+
* Updates the requested blobs. If {@code infos.length == 0} an empty list is returned. If
292+
* {@code infos.length > 1} a batch request is used to update blobs.
293+
*
294+
* @param storage the storage service used to issue the request
295+
* @param infos the blobs to update
296+
* @return an immutable list of {@code Blob} objects. If a blob does not exist or access to it has
297+
* been denied the corresponding item in the list is {@code null}.
298+
* @throws StorageException upon failure
299+
*/
300+
public static List<Blob> update(final Storage storage, BlobInfo... infos) {
301+
checkNotNull(storage);
302+
checkNotNull(infos);
303+
if (infos.length == 0) {
304+
return Collections.emptyList();
305+
}
306+
return Collections.unmodifiableList(Lists.transform(storage.update(infos),
307+
new Function<BlobInfo, Blob>() {
308+
@Override
309+
public Blob apply(BlobInfo f) {
310+
return f != null ? new Blob(storage, f) : null;
311+
}
312+
}));
313+
}
314+
315+
/**
316+
* Deletes the requested blobs. If {@code infos.length == 0} an empty list is returned. If
317+
* {@code infos.length > 1} a batch request is used to delete blobs.
318+
*
319+
* @param storage the storage service used to issue the request
320+
* @param infos the blobs to delete
321+
* @return an immutable list of booleans. If a blob has been deleted the corresponding item in the
322+
* list is {@code true}. If deletion failed or access to the resource was denied the item is
323+
* {@code false}.
324+
* @throws StorageException upon failure
325+
*/
326+
public static List<Boolean> delete(Storage storage, BlobInfo... infos) {
327+
checkNotNull(storage);
328+
checkNotNull(infos);
329+
if (infos.length == 0) {
330+
return Collections.emptyList();
331+
}
332+
return storage.delete(infos);
333+
}
259334
}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.gcloud.storage.Storage.BucketTargetOption;
2626

2727
import java.util.ArrayList;
28+
import java.util.Collections;
2829
import java.util.List;
2930
import java.util.Objects;
3031

@@ -146,21 +147,26 @@ public Blob get(String blob, BlobSourceOption... options) {
146147
/**
147148
* Returns a list of requested blobs in this bucket. Blobs that do not exist are null.
148149
*
149-
* @param blobNames names of the requested blobs
150+
* @param blobName1 first blob to get
151+
* @param blobName2 second blob to get
152+
* @param blobNames other blobs to get
153+
* @return an immutable list of {@code Blob} objects.
150154
* @throws StorageException upon failure
151155
*/
152-
public List<Blob> getAll(String... blobNames) {
156+
public List<Blob> get(String blobName1, String blobName2, String... blobNames) {
153157
BatchRequest.Builder batch = BatchRequest.builder();
154-
for (String blobName : blobNames) {
155-
batch.get(info.name(), blobName);
158+
batch.get(info.name(), blobName1);
159+
batch.get(info.name(), blobName2);
160+
for (String name : blobNames) {
161+
batch.get(info.name(), name);
156162
}
157163
List<Blob> blobs = new ArrayList<>(blobNames.length);
158164
BatchResponse response = storage.apply(batch.build());
159165
for (BatchResponse.Result<BlobInfo> result : response.gets()) {
160166
BlobInfo blobInfo = result.get();
161167
blobs.add(blobInfo != null ? new Blob(storage, blobInfo) : null);
162168
}
163-
return blobs;
169+
return Collections.unmodifiableList(blobs);
164170
}
165171

166172
/**

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,14 @@ public static Builder builder() {
563563
*/
564564
BlobInfo update(BlobInfo blobInfo, BlobTargetOption... options);
565565

566+
/**
567+
* Update blob information.
568+
*
569+
* @return the updated blob
570+
* @throws StorageException upon failure
571+
*/
572+
BlobInfo update(BlobInfo blobInfo);
573+
566574
/**
567575
* Delete the requested bucket.
568576
*
@@ -644,4 +652,35 @@ public static Builder builder() {
644652
* @see <a href="https://cloud.google.com/storage/docs/access-control#Signed-URLs">Signed-URLs</a>
645653
*/
646654
URL signUrl(BlobInfo blobInfo, long expirationTimeInSeconds, SignUrlOption... options);
655+
656+
/**
657+
* Gets the requested blobs. A batch request is used to perform this call.
658+
*
659+
* @param blobInfos blobs to get
660+
* @return an immutable list of {@code BlobInfo} objects. If a blob does not exist or access to it
661+
* has been denied the corresponding item in the list is {@code null}.
662+
* @throws StorageException upon failure
663+
*/
664+
List<BlobInfo> get(BlobInfo... blobInfos);
665+
666+
/**
667+
* Updates the requested blobs. A batch request is used to perform this call.
668+
*
669+
* @param blobInfos blobs to update
670+
* @return an immutable list of {@code BlobInfo} objects. If a blob does not exist or access to it
671+
* has been denied the corresponding item in the list is {@code null}.
672+
* @throws StorageException upon failure
673+
*/
674+
List<BlobInfo> update(BlobInfo... blobInfos);
675+
676+
/**
677+
* Deletes the requested blobs. A batch request is used to perform this call.
678+
*
679+
* @param blobInfos blobs to delete
680+
* @return an immutable list of booleans. If a blob has been deleted the corresponding item in the
681+
* list is {@code true}. If deletion failed or access to the resource was denied the item is
682+
* {@code false}.
683+
* @throws StorageException upon failure
684+
*/
685+
List<Boolean> delete(BlobInfo... blobInfos);
647686
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import java.security.Signature;
6363
import java.security.SignatureException;
6464
import java.util.Arrays;
65+
import java.util.Collections;
6566
import java.util.EnumMap;
6667
import java.util.List;
6768
import java.util.Map;
@@ -348,6 +349,11 @@ public StorageObject call() {
348349
}
349350
}
350351

352+
@Override
353+
public BlobInfo update(BlobInfo blobInfo) {
354+
return update(blobInfo, new BlobTargetOption[0]);
355+
}
356+
351357
@Override
352358
public boolean delete(String bucket, BucketSourceOption... options) {
353359
final com.google.api.services.storage.model.Bucket bucketPb = BucketInfo.of(bucket).toPb();
@@ -577,6 +583,46 @@ public URL signUrl(BlobInfo blobInfo, long expiration, SignUrlOption... options)
577583
}
578584
}
579585

586+
@Override
587+
public List<BlobInfo> get(BlobInfo... blobInfos) {
588+
BatchRequest.Builder requestBuilder = BatchRequest.builder();
589+
for (BlobInfo blobInfo : blobInfos) {
590+
requestBuilder.get(blobInfo.bucket(), blobInfo.name());
591+
}
592+
BatchResponse response = apply(requestBuilder.build());
593+
return Collections.unmodifiableList(transformResultList(response.gets(), null));
594+
}
595+
596+
@Override
597+
public List<BlobInfo> update(BlobInfo... blobInfos) {
598+
BatchRequest.Builder requestBuilder = BatchRequest.builder();
599+
for (BlobInfo blobInfo : blobInfos) {
600+
requestBuilder.update(blobInfo);
601+
}
602+
BatchResponse response = apply(requestBuilder.build());
603+
return Collections.unmodifiableList(transformResultList(response.updates(), null));
604+
}
605+
606+
@Override
607+
public List<Boolean> delete(BlobInfo... blobInfos) {
608+
BatchRequest.Builder requestBuilder = BatchRequest.builder();
609+
for (BlobInfo blobInfo : blobInfos) {
610+
requestBuilder.delete(blobInfo.bucket(), blobInfo.name());
611+
}
612+
BatchResponse response = apply(requestBuilder.build());
613+
return Collections.unmodifiableList(transformResultList(response.deletes(), Boolean.FALSE));
614+
}
615+
616+
private static <T extends Serializable> List<T> transformResultList(
617+
List<BatchResponse.Result<T>> results, final T errorValue) {
618+
return Lists.transform(results, new Function<BatchResponse.Result<T>, T>() {
619+
@Override
620+
public T apply(BatchResponse.Result<T> f) {
621+
return f.failed() ? errorValue : f.get();
622+
}
623+
});
624+
}
625+
580626
private Map<StorageRpc.Option, ?> optionMap(Long generation, Long metaGeneration,
581627
Iterable<? extends Option> options) {
582628
return optionMap(generation, metaGeneration, options, false);

0 commit comments

Comments
 (0)