Skip to content

Commit 28ab577

Browse files
committed
Merge pull request #58 from aozarov/master
add metadata update to example and fix builder user-settable fields
2 parents a55d6ec + f409c22 commit 28ab577

File tree

11 files changed

+433
-94
lines changed

11 files changed

+433
-94
lines changed

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

Lines changed: 154 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
/**
4747
* An example of using the Google Cloud Storage.
4848
* <p>
49-
* This example demonstrates a simple/typical usage.
49+
* This example demonstrates a simple/typical storage usage.
5050
* <p>
5151
* Steps needed for running the example:
5252
* <ol>
@@ -57,9 +57,14 @@
5757
* -Dexec.args="[<project_id>] list [<bucket>]| info [<bucket> [<file>]]|
5858
* download <bucket> <path> [local_file]| upload <local_file> <bucket> [<path>]|
5959
* delete <bucket> <path>+| cp <from_bucket> <from_path> <to_bucket> <to_path>|
60-
* compose <bucket> <from_path>+ <to_path>"}
60+
* compose <bucket> <from_path>+ <to_path>| update_metadata <bucket> <file> [key=value]*"}
6161
* </li>
6262
* </ol>
63+
*
64+
* The first parameter is an optional project_id (logged-in project will be used if not supplied).
65+
* Second parameter is a Storage operation (list, delete, compose,...) to demonstrate the its
66+
* usage. Any other arguments are specific to the operation.
67+
* See each action's run method for the specific Storage interaction.
6368
*/
6469
public class StorageExample {
6570

@@ -112,24 +117,36 @@ public String params() {
112117
}
113118
}
114119

120+
/**
121+
* This class demonstrates how to retrieve Bucket or Blob metadata.
122+
* If more than one blob is supplied a Batch operation would be used to get all blobs metadata
123+
* in a single RPC.
124+
*
125+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/get">Objects: get</a>
126+
*/
115127
private static class InfoAction extends BlobsAction {
116128
@Override
117129
public void run(StorageService storage, Blob... blobs) {
118-
119-
120130
if (blobs.length == 1) {
121131
if (blobs[0].name().isEmpty()) {
122-
System.out.println(storage.get(blobs[0].bucket()));
132+
// get Bucket
133+
Bucket bucket = storage.get(blobs[0].bucket());
134+
System.out.println("Bucket info: " + bucket);
123135
} else {
124-
System.out.println(storage.get(blobs[0].bucket(), blobs[0].name()));
136+
// get Blob
137+
Blob blob = storage.get(blobs[0].bucket(), blobs[0].name());
138+
System.out.println("Blob info: " + blob);
125139
}
126140
} else {
141+
// use batch to get multiple blobs.
127142
BatchRequest.Builder batch = BatchRequest.builder();
128143
for (Blob blob : blobs) {
129144
batch.get(blob.bucket(), blob.name());
130145
}
131146
BatchResponse response = storage.apply(batch.build());
132-
System.out.println(response.gets());
147+
for (BatchResponse.Result<Blob> result : response.gets()) {
148+
System.out.println(result.get());
149+
}
133150
}
134151
}
135152

@@ -147,22 +164,45 @@ public String params() {
147164
}
148165
}
149166

167+
/**
168+
* This class demonstrates how to delete a blob.
169+
* If more than one blob is supplied a Batch operation would be used to delete all requested
170+
* blobs in a single RPC.
171+
*
172+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/delete">Objects: delete</a>
173+
*/
150174
private static class DeleteAction extends BlobsAction {
151175
@Override
152176
public void run(StorageService storage, Blob... blobs) {
153177
if (blobs.length == 1) {
154-
System.out.println(storage.delete(blobs[0].bucket(), blobs[0].name()));
178+
boolean wasDeleted = storage.delete(blobs[0].bucket(), blobs[0].name());
179+
if (wasDeleted) {
180+
System.out.println("Blob " + blobs[0] + " was deleted");
181+
}
155182
} else {
183+
// use batch operation
156184
BatchRequest.Builder batch = BatchRequest.builder();
157185
for (Blob blob : blobs) {
158186
batch.delete(blob.bucket(), blob.name());
159187
}
188+
int index = 0;
160189
BatchResponse response = storage.apply(batch.build());
161-
System.out.println(response.deletes());
190+
for (BatchResponse.Result<Boolean> result : response.deletes()) {
191+
if (result.get()) {
192+
// request order is maintained
193+
System.out.println("Blob " + blobs[index] + " was deleted");
194+
}
195+
index++;
196+
}
162197
}
163198
}
164199
}
165200

201+
/**
202+
* This class demonstrates how to list buckets or a bucket's blobs.
203+
*
204+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/list">Objects: list</a>
205+
*/
166206
private static class ListAction extends StorageAction<String> {
167207

168208
@Override
@@ -179,10 +219,12 @@ String parse(String... args) {
179219
@Override
180220
public void run(StorageService storage, String bucket) {
181221
if (bucket == null) {
222+
// list buckets
182223
for (Bucket b : storage.list()) {
183224
System.out.println(b);
184225
}
185226
} else {
227+
// list a bucket's blobs
186228
for (Blob b : storage.list(bucket)) {
187229
System.out.println(b);
188230
}
@@ -195,13 +237,24 @@ public String params() {
195237
}
196238
}
197239

240+
/**
241+
* This class demonstrates how to create a new Blob or to update its content.
242+
*
243+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/insert">Objects: insert</a>
244+
*/
198245
private static class UploadAction extends StorageAction<Tuple<Path, Blob>> {
199246
@Override
200247
public void run(StorageService storage, Tuple<Path, Blob> tuple) throws Exception {
201-
if (Files.size(tuple.x()) > 1024) {
202-
try (BlobWriteChannel writer = storage.writer(tuple.y())) {
248+
run(storage, tuple.x(), tuple.y());
249+
}
250+
251+
private void run(StorageService storage, Path uploadFrom, Blob blob) throws IOException {
252+
if (Files.size(uploadFrom) > 1_000_000) {
253+
// When content is not available or large (1MB or more) it is recommended
254+
// to write it in chunks via the blob's channel writer.
255+
try (BlobWriteChannel writer = storage.writer(blob)) {
203256
byte[] buffer = new byte[1024];
204-
try (InputStream input = Files.newInputStream(tuple.x())) {
257+
try (InputStream input = Files.newInputStream(uploadFrom)) {
205258
int limit;
206259
while ((limit = input.read(buffer)) >= 0) {
207260
try {
@@ -213,9 +266,11 @@ public void run(StorageService storage, Tuple<Path, Blob> tuple) throws Exceptio
213266
}
214267
}
215268
} else {
216-
byte[] bytes = Files.readAllBytes(tuple.x());
217-
System.out.println(storage.create(tuple.y(), bytes));
269+
byte[] bytes = Files.readAllBytes(uploadFrom);
270+
// create the blob in one request.
271+
storage.create(blob, bytes);
218272
}
273+
System.out.println("Blob was created");
219274
}
220275

221276
@Override
@@ -235,22 +290,37 @@ public String params() {
235290
}
236291
}
237292

293+
/**
294+
* This class demonstrates how read a blob's content.
295+
* The example will dump the content to a local file if one was given or write
296+
* it to stdout otherwise.
297+
*
298+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/get">Objects: get</a>
299+
*/
238300
private static class DownloadAction extends StorageAction<Tuple<Blob, Path>> {
239301

240302
@Override
241303
public void run(StorageService storage, Tuple<Blob, Path> tuple) throws IOException {
242-
Blob blob = storage.get(tuple.x().bucket(), tuple.x().name());
304+
run(storage, tuple.x().bucket(), tuple.x().name(), tuple.y());
305+
}
306+
307+
private void run(StorageService storage, String bucket, String blobName, Path downloadTo)
308+
throws IOException {
309+
Blob blob = storage.get(bucket, blobName);
243310
if (blob == null) {
244311
System.out.println("No such object");
245312
return;
246313
}
247314
PrintStream writeTo = System.out;
248-
if (tuple.y() != null) {
249-
writeTo = new PrintStream(new FileOutputStream(tuple.y().toFile()));
315+
if (downloadTo != null) {
316+
writeTo = new PrintStream(new FileOutputStream(downloadTo.toFile()));
250317
}
251-
if (blob.size() < 1024) {
252-
writeTo.write(storage.load(blob.bucket(), blob.name()));
318+
if (blob.size() < 1_000_000) {
319+
// Blob is small read all its content in one request
320+
byte[] content = storage.load(blob.bucket(), blob.name());
321+
writeTo.write(content);
253322
} else {
323+
// When Blob size is big or unknown use the blob's channel reader.
254324
try (BlobReadChannel reader = storage.reader(blob.bucket(), blob.name())) {
255325
WritableByteChannel channel = Channels.newChannel(writeTo);
256326
ByteBuffer bytes = ByteBuffer.allocate(64 * 1024);
@@ -261,7 +331,7 @@ public void run(StorageService storage, Tuple<Blob, Path> tuple) throws IOExcept
261331
}
262332
}
263333
}
264-
if (tuple.y() == null) {
334+
if (downloadTo == null) {
265335
writeTo.println();
266336
} else {
267337
writeTo.close();
@@ -291,10 +361,16 @@ public String params() {
291361
}
292362
}
293363

364+
/**
365+
* This class demonstrates how to use the copy command.
366+
*
367+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/copy">Objects: copy</a>
368+
*/
294369
private static class CopyAction extends StorageAction<CopyRequest> {
295370
@Override
296371
public void run(StorageService storage, CopyRequest request) {
297-
System.out.println(storage.copy(request));
372+
Blob copiedBlob = storage.copy(request);
373+
System.out.println("Copied " + copiedBlob);
298374
}
299375

300376
@Override
@@ -311,10 +387,16 @@ public String params() {
311387
}
312388
}
313389

390+
/**
391+
* This class demonstrates how to use the compose command.
392+
*
393+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/compose">Objects: compose</a>
394+
*/
314395
private static class ComposeAction extends StorageAction<ComposeRequest> {
315396
@Override
316397
public void run(StorageService storage, ComposeRequest request) {
317-
System.out.println(storage.compose(request));
398+
Blob composedBlob = storage.compose(request);
399+
System.out.println("Composed " + composedBlob);
318400
}
319401

320402
@Override
@@ -336,6 +418,54 @@ public String params() {
336418
}
337419
}
338420

421+
/**
422+
* This class demonstrates how to update a blob's metadata.
423+
*
424+
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/update">Objects: update</a>
425+
*/
426+
private static class UpdateMetadata extends StorageAction<Tuple<Blob, Map<String, String>>> {
427+
428+
@Override
429+
public void run(StorageService storage, Tuple<Blob, Map<String, String>> tuple)
430+
throws IOException {
431+
run(storage, tuple.x().bucket(), tuple.x().name(), tuple.y());
432+
}
433+
434+
private void run(StorageService storage, String bucket, String blobName,
435+
Map<String, String> metadata) {
436+
Blob blob = storage.get(bucket, blobName);
437+
if (blob == null) {
438+
System.out.println("No such object");
439+
return;
440+
}
441+
blob = storage.update(blob.toBuilder().metadata(metadata).build());
442+
System.out.println("Updated " + blob);
443+
}
444+
445+
@Override
446+
Tuple<Blob, Map<String, String>> parse(String... args) {
447+
if (args.length < 2) {
448+
throw new IllegalArgumentException();
449+
}
450+
Blob blob = Blob.of(args[0], args[1]);
451+
Map<String, String> metadata = new HashMap<>();
452+
for (int i = 2; i < args.length; i++) {
453+
int idx = args[i].indexOf('=');
454+
if (idx < 0) {
455+
metadata.put(args[i], "");
456+
} else {
457+
metadata.put(args[i].substring(0, idx), args[i].substring(idx + 1));
458+
}
459+
}
460+
return Tuple.of(blob, metadata);
461+
}
462+
463+
@Override
464+
public String params() {
465+
return "<bucket> <path> [local_file]";
466+
}
467+
}
468+
339469
static {
340470
ACTIONS.put("info", new InfoAction());
341471
ACTIONS.put("delete", new DeleteAction());
@@ -344,6 +474,7 @@ public String params() {
344474
ACTIONS.put("download", new DownloadAction());
345475
ACTIONS.put("cp", new CopyAction());
346476
ACTIONS.put("compose", new ComposeAction());
477+
ACTIONS.put("update_metadata", new UpdateMetadata());
347478
}
348479

349480
public static void printUsage() {
@@ -378,7 +509,7 @@ public static void main(String... args) throws Exception {
378509
args = Arrays.copyOfRange(args, 1, args.length);
379510
}
380511
if (action == null) {
381-
System.out.println("Unrecognized action '" + args[1] + "'");
512+
System.out.println("Unrecognized action.");
382513
printUsage();
383514
return;
384515
}

0 commit comments

Comments
 (0)