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>
6060 * 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 */
6469public class StorageExample {
6570
@@ -112,24 +117,34 @@ 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+ */
115125 private static class InfoAction extends BlobsAction {
116126 @ Override
117127 public void run (StorageService storage , Blob ... blobs ) {
118-
119-
120128 if (blobs .length == 1 ) {
121129 if (blobs [0 ].name ().isEmpty ()) {
122- System .out .println (storage .get (blobs [0 ].bucket ()));
130+ // get Bucket
131+ Bucket bucket = storage .get (blobs [0 ].bucket ());
132+ System .out .println ("Bucket info: " + bucket );
123133 } else {
124- System .out .println (storage .get (blobs [0 ].bucket (), blobs [0 ].name ()));
134+ // get Blob
135+ Blob blob = storage .get (blobs [0 ].bucket (), blobs [0 ].name ());
136+ System .out .println ("Blob info: " + blob );
125137 }
126138 } else {
139+ // use batch to get multiple blobs.
127140 BatchRequest .Builder batch = BatchRequest .builder ();
128141 for (Blob blob : blobs ) {
129142 batch .get (blob .bucket (), blob .name ());
130143 }
131144 BatchResponse response = storage .apply (batch .build ());
132- System .out .println (response .gets ());
145+ for (BatchResponse .Result <Blob > result : response .gets ()) {
146+ System .out .println (result .get ());
147+ }
133148 }
134149 }
135150
@@ -147,22 +162,41 @@ public String params() {
147162 }
148163 }
149164
165+ /**
166+ * This class demonstrates how to delete a blob.
167+ * If more than one blob is supplied a Batch operation would be used to delete all requested
168+ * blobs in a single RPC.
169+ */
150170 private static class DeleteAction extends BlobsAction {
151171 @ Override
152172 public void run (StorageService storage , Blob ... blobs ) {
153173 if (blobs .length == 1 ) {
154- System .out .println (storage .delete (blobs [0 ].bucket (), blobs [0 ].name ()));
174+ boolean wasDeleted = storage .delete (blobs [0 ].bucket (), blobs [0 ].name ());
175+ if (wasDeleted ) {
176+ System .out .println ("Blob " + blobs [0 ] + " was deleted" );
177+ }
155178 } else {
179+ // use batch operation
156180 BatchRequest .Builder batch = BatchRequest .builder ();
157181 for (Blob blob : blobs ) {
158182 batch .delete (blob .bucket (), blob .name ());
159183 }
184+ int index = 0 ;
160185 BatchResponse response = storage .apply (batch .build ());
161- System .out .println (response .deletes ());
186+ for (BatchResponse .Result <Boolean > result : response .deletes ()) {
187+ if (result .get ()) {
188+ // request order is maintained
189+ System .out .println ("Blob " + blobs [index ] + " was deleted" );
190+ }
191+ index ++;
192+ }
162193 }
163194 }
164195 }
165196
197+ /**
198+ * This class demonstrates how to list buckets or a bucket's blobs.
199+ */
166200 private static class ListAction extends StorageAction <String > {
167201
168202 @ Override
@@ -179,10 +213,12 @@ String parse(String... args) {
179213 @ Override
180214 public void run (StorageService storage , String bucket ) {
181215 if (bucket == null ) {
216+ // list buckets
182217 for (Bucket b : storage .list ()) {
183218 System .out .println (b );
184219 }
185220 } else {
221+ // list a bucket's blobs
186222 for (Blob b : storage .list (bucket )) {
187223 System .out .println (b );
188224 }
@@ -195,13 +231,22 @@ public String params() {
195231 }
196232 }
197233
234+ /**
235+ * This class demonstrates how to create a new Blob or to update its content.
236+ */
198237 private static class UploadAction extends StorageAction <Tuple <Path , Blob >> {
199238 @ Override
200239 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 ())) {
240+ run (storage , tuple .x (), tuple .y ());
241+ }
242+
243+ private void run (StorageService storage , Path uploadFrom , Blob blob ) throws IOException {
244+ if (Files .size (uploadFrom ) > 1_000_000 ) {
245+ // When content is not available or large (1MB or more) it is recommended
246+ // to write it in chunks via the blob's channel writer.
247+ try (BlobWriteChannel writer = storage .writer (blob )) {
203248 byte [] buffer = new byte [1024 ];
204- try (InputStream input = Files .newInputStream (tuple . x () )) {
249+ try (InputStream input = Files .newInputStream (uploadFrom )) {
205250 int limit ;
206251 while ((limit = input .read (buffer )) >= 0 ) {
207252 try {
@@ -213,9 +258,11 @@ public void run(StorageService storage, Tuple<Path, Blob> tuple) throws Exceptio
213258 }
214259 }
215260 } else {
216- byte [] bytes = Files .readAllBytes (tuple .x ());
217- System .out .println (storage .create (tuple .y (), bytes ));
261+ byte [] bytes = Files .readAllBytes (uploadFrom );
262+ // create the blob in one request.
263+ storage .create (blob , bytes );
218264 }
265+ System .out .println ("Blob was created" );
219266 }
220267
221268 @ Override
@@ -235,22 +282,35 @@ public String params() {
235282 }
236283 }
237284
285+ /**
286+ * This class demonstrates how read a blob's content.
287+ * The example will dump the content to a local file if one was given or write
288+ * it to stdout otherwise.
289+ */
238290 private static class DownloadAction extends StorageAction <Tuple <Blob , Path >> {
239291
240292 @ Override
241293 public void run (StorageService storage , Tuple <Blob , Path > tuple ) throws IOException {
242- Blob blob = storage .get (tuple .x ().bucket (), tuple .x ().name ());
294+ run (storage , tuple .x ().bucket (), tuple .x ().name (), tuple .y ());
295+ }
296+
297+ private void run (StorageService storage , String bucket , String blobName , Path downloadTo )
298+ throws IOException {
299+ Blob blob = storage .get (bucket , blobName );
243300 if (blob == null ) {
244301 System .out .println ("No such object" );
245302 return ;
246303 }
247304 PrintStream writeTo = System .out ;
248- if (tuple . y () != null ) {
249- writeTo = new PrintStream (new FileOutputStream (tuple . y () .toFile ()));
305+ if (downloadTo != null ) {
306+ writeTo = new PrintStream (new FileOutputStream (downloadTo .toFile ()));
250307 }
251- if (blob .size () < 1024 ) {
252- writeTo .write (storage .load (blob .bucket (), blob .name ()));
308+ if (blob .size () < 1_000_000 ) {
309+ // Blob is small read all its content in one request
310+ byte [] content = storage .load (blob .bucket (), blob .name ());
311+ writeTo .write (content );
253312 } else {
313+ // When Blob size is big or unknown use the blob's channel reader.
254314 try (BlobReadChannel reader = storage .reader (blob .bucket (), blob .name ())) {
255315 WritableByteChannel channel = Channels .newChannel (writeTo );
256316 ByteBuffer bytes = ByteBuffer .allocate (64 * 1024 );
@@ -261,7 +321,7 @@ public void run(StorageService storage, Tuple<Blob, Path> tuple) throws IOExcept
261321 }
262322 }
263323 }
264- if (tuple . y () == null ) {
324+ if (downloadTo == null ) {
265325 writeTo .println ();
266326 } else {
267327 writeTo .close ();
@@ -291,10 +351,16 @@ public String params() {
291351 }
292352 }
293353
354+ /**
355+ * This class demonstrates how to use the copy command.
356+ *
357+ * @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/copy">Object copy</a>
358+ */
294359 private static class CopyAction extends StorageAction <CopyRequest > {
295360 @ Override
296361 public void run (StorageService storage , CopyRequest request ) {
297- System .out .println (storage .copy (request ));
362+ Blob copiedBlob = storage .copy (request );
363+ System .out .println ("Copied " + copiedBlob );
298364 }
299365
300366 @ Override
@@ -311,10 +377,16 @@ public String params() {
311377 }
312378 }
313379
380+ /**
381+ * This class demonstrates how to use the compose command.
382+ *
383+ * @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/compose">Object compose</a>
384+ */
314385 private static class ComposeAction extends StorageAction <ComposeRequest > {
315386 @ Override
316387 public void run (StorageService storage , ComposeRequest request ) {
317- System .out .println (storage .compose (request ));
388+ Blob composedBlob = storage .compose (request );
389+ System .out .println ("Composed " + composedBlob );
318390 }
319391
320392 @ Override
@@ -336,19 +408,28 @@ public String params() {
336408 }
337409 }
338410
411+ /**
412+ * This class demonstrates how to update a blob's metadata.
413+ *
414+ * @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/compose">Object compose</a>
415+ */
339416 private static class UpdateMetadata extends StorageAction <Tuple <Blob , Map <String , String >>> {
340417
341418 @ Override
342419 public void run (StorageService storage , Tuple <Blob , Map <String , String >> tuple )
343420 throws IOException {
344- Blob blob = storage .get (tuple .x ().bucket (), tuple .x ().name ());
421+ run (storage , tuple .x ().bucket (), tuple .x ().name (), tuple .y ());
422+ }
423+
424+ private void run (StorageService storage , String bucket , String blobName ,
425+ Map <String , String > metadata ) {
426+ Blob blob = storage .get (bucket , blobName );
345427 if (blob == null ) {
346428 System .out .println ("No such object" );
347429 return ;
348430 }
349- blob = blob .toBuilder ().metadata (tuple .y ()).build ();
350- System .out .println ("before: " + blob );
351- System .out .println (storage .update (blob ));
431+ blob = storage .update (blob .toBuilder ().metadata (metadata ).build ());
432+ System .out .println ("Updated " + blob );
352433 }
353434
354435 @ Override
@@ -357,7 +438,7 @@ Tuple<Blob, Map<String, String>> parse(String... args) {
357438 throw new IllegalArgumentException ();
358439 }
359440 Blob blob = Blob .of (args [0 ], args [1 ]);
360- Map <String , String > metadata = new HashMap <>();
441+ Map <String , String > metadata = new HashMap <>();
361442 for (int i = 2 ; i < args .length ; i ++) {
362443 int idx = args [i ].indexOf ('=' );
363444 if (idx < 0 ) {
0 commit comments