001package Torello.Java; 002 003import Torello.Java.StrIndent; 004 005import static Torello.Java.C.*; 006 007import java.util.*; 008import java.io.*; 009import java.util.zip.*; 010 011import com.google.cloud.storage.*; 012import com.google.auth.oauth2.*; 013 014/** 015 * <B><CODE>Load File Exception Catch</CODE></B> provides an eloquent way for printing standardized 016 * <I>(consistent-looking)</I> error messages to terminal if a data-file fails to load from the 017 * file-system, and subsequently halting the JVM - immediately. 018 * 019 * <EMBED CLASS='external-html' DATA-FILE-ID=LFEC> 020 */ 021@Torello.JavaDoc.StaticFunctional 022public class LFEC 023{ 024 private LFEC() { } 025 026 027 // ******************************************************************************************** 028 // ******************************************************************************************** 029 // These are error-printing methods. 030 // ******************************************************************************************** 031 // ******************************************************************************************** 032 033 034 /** 035 * This prints a message and a location and halts the current thread immediately. (Halts the 036 * program) The entire rational behind the {@code class LFEC} is to facilitate loading 037 * data-files, and forcing an immediate program halt if this operation fails. Generally, 038 * during development and debugging, failing to read from a data-file is serious enough to 039 * warrant stopping the software until the issue is fixed. "Hobbling along without reading 040 * the data-files" makes little sense. 041 * 042 * <BR /><BR />When the software is being released or distributed, the philosophy turns to 043 * loading mission critical data out of data-files in a java jar-file. If the jar-file is 044 * corrupted and those files are not present, generally <I>this situation would <B>also 045 * warrant</B> halting the program execution immediately until the jar file is fixed.</I> 046 * 047 * @param t An exception, error or other {@code Throwable} that generated a problem when 048 * attempting to read a data-file. 049 * 050 * @param message This is an internally generated message explaining what has occurred. 051 */ 052 protected static void ERROR_EXIT(Throwable t, String message) 053 { 054 System.out.println( 055 '\n' + 056 "There was an error loading a data-file, and program-execution is being halted " + 057 "immediately.\n" + 058 "Problem Encountered With:\n" + StrIndent.indent(message, 4) + "\n" + 059 "Exception or Error Message:\n" + 060 EXCC.toString(t) + "\n\n" + 061 "Exiting Program, Fatal Error Loading Critical Data File." 062 ); 063 064 System.exit(1); 065 } 066 067 /** 068 * This prints a message and a location and halts the current thread immediately. (Halts the 069 * program) The entire rational behind the {@code class LFEC} is to facilitate loading 070 * data-files, and forcing an immediate program halt if this operation fails. Generally, 071 * during development and debugging, failing to read from a data-file is serious enough to 072 * warrant stopping the software until the issue is fixed. "Hobbling along without reading 073 * the data-files" makes little sense. 074 * 075 * <BR /><BR />When the software is being released or distributed, the philosophy turns to 076 * loading mission critical data out of data-files in a java jar-file. If the jar-file is 077 * corrupted and those files are not present, generally <I>this situation would <B>also 078 * warrant</B> halting the program execution immediately until the jar file is fixed.</I> 079 * 080 * @param message This is an internally generated message explaining what has occurred. 081 */ 082 protected static void ERROR_EXIT(String message) 083 { 084 System.out.println( 085 '\n' + 086 "There was an error loading a data-file, and program-execution is being halted " + 087 "immediately.\n" + 088 "Problem Encountered With:\n" + message + "\n\n" + 089 "Exiting Program, Fatal Error Loading Critical Data File." 090 ); 091 092 System.exit(1); 093 } 094 095 096 // ******************************************************************************************** 097 // ******************************************************************************************** 098 // These are the data-loading methods. 099 // ******************************************************************************************** 100 // ******************************************************************************************** 101 102 103 /** 104 * Loads a file directly into a java-{@code String.} If this file fails to load, it halts the 105 * run-time environment. 106 * 107 * @param f This is a {@code java.lang.String} that contains the filename. 108 * 109 * @return The returned {@code String} contains the entire contents of the file. 110 * 111 * @see FileRW#loadFileToString(String) 112 * @see #ERROR_EXIT(Throwable, String) 113 */ 114 public static String loadFile(String f) 115 { 116 try 117 { return FileRW.loadFileToString(f); } 118 119 catch (Throwable t) 120 { ERROR_EXIT(t, "FileRW.loadFileToString(\"" + f + "\")"); } 121 122 throw new UnreachableError(); // Should not be possible to reach this statement 123 } 124 125 /** 126 * Loads a file directory to a string <I>from a java jar-file</I>. It halts the program, and 127 * prints a detailed message if any {@code Error's} or {@code Exception's} were thrown. The 128 * directory inside the jar-file where this file may be located identified by parameter 129 * {@code class 'classLoaderClass'}. 130 * 131 * @param classLoaderClass <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_CLASS_LOAD_C> 132 * <EMBED CLASS='external-html' DATA-FILE-ID=RAWTYPES> 133 * 134 * @param f This is a {@code String} that contains the filename of the data-file that needs 135 * to be loaded. It is a 'relative file-name' that is relative to the jar-file / directory pair 136 * location that the class loader identifies using the {@code Class} from parameter 137 * {@code 'classLoaderClass'} 138 * 139 * @return The returned string contains the entire contents of the file. 140 * 141 * @see #ERROR_EXIT(Throwable, String) 142 */ 143 public static String loadFile_JAR(Class<?> classLoaderClass, String f) 144 { 145 // These are 'java.lang.AutoCloseable', and java handles them automatically 146 // if there is an exception 147 148 try ( 149 InputStream is = classLoaderClass.getResourceAsStream(f); 150 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 151 ) 152 { 153 String s = ""; 154 StringBuffer sb = new StringBuffer(); 155 156 while ((s = br.readLine()) != null) sb.append(s + "\n"); 157 158 return sb.toString(); 159 } 160 161 catch (Throwable t) 162 { 163 ERROR_EXIT( 164 t, 165 "Error loading text-file [" + f + "] from jar-file.\n" + 166 "Class loader attempted to use information in class " + 167 "[" + classLoaderClass.getCanonicalName() + "], but failed." 168 ); 169 } 170 171 throw new UnreachableError(); // Should NOT be possible to reach this statement... 172 } 173 174 /** 175 * Loads a file <I>from a java jar-file</I> using an {@code InputStream} and copies that file, 176 * byte-for-byte, to {@code 'targetFileName'}. A detailed message is printed if any 177 * {@code Error's} or {@code Exception's} were thrown. The directory inside the jar-file 178 * where this file may be located identified by parameter {@code class 'classLoaderClass'}. 179 * 180 * @param classLoaderClass <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_CLASS_LOAD_C> 181 * <EMBED CLASS='external-html' DATA-FILE-ID=RAWTYPES> 182 * 183 * @param fileName This is a {@code String} that contains the filename of the data-file that 184 * needs to be copied. It is a 'relative file-name' that is relative to the jar-file / 185 * directory pair location that the class loader identifies using the {@code Class} from 186 * parameter {@code 'classLoaderClass'}. 187 * 188 * @param targetFileName This is the file and directory that contains the target location 189 * (as a {@code String}) to where the file should be copied. 190 * 191 * @see #ERROR_EXIT(Throwable, String) 192 */ 193 public static void copyFile_JAR 194 (Class<?> classLoaderClass, String fileName, String targetFileName) 195 { 196 // These are 'java.lang.AutoCloseable', and java handles them automatically 197 // if there is an exception 198 199 try ( 200 InputStream is = classLoaderClass.getResourceAsStream(fileName); 201 FileOutputStream fos = new FileOutputStream(targetFileName); 202 ) 203 { 204 byte[] b = new byte[5000]; 205 int result = 0; 206 207 while ((result = is.read(b)) != -1) fos.write(b, 0, result); 208 } 209 210 catch (Throwable t) 211 { 212 ERROR_EXIT( 213 t, 214 "Error copying file [" + fileName + "] from jar-file to " + 215 "[" + targetFileName + "].\n" + 216 "Class loader attempted to use information in class " + 217 "[" + classLoaderClass.getCanonicalName() + "]." 218 ); 219 } 220 } 221 222 /** 223 * This loads a file to a {@code Vector} of {@code String's}. It halts the program, and prints 224 * a detailed message if any errors or exceptions occur. 225 * 226 * @param f The name of the file to load 227 * 228 * @param includeNewLine States whether the {@code '\n'} (new-line) character should be appended 229 * to each element of the returned {@code Vector<String>}. 230 * 231 * @return a {@code Vector} of {@code String's}, where each element in the {@code Vector} is a 232 * line retrieved from the text-file. 233 * 234 * @see #ERROR_EXIT(Throwable, String) 235 */ 236 public static Vector<String> loadFileToVector(String f, boolean includeNewLine) 237 { 238 try 239 { return FileRW.loadFileToVector(f, includeNewLine); } 240 241 catch (Throwable t) 242 { 243 ERROR_EXIT( 244 t, 245 "Attempting to Invoke this Load-Method with these Arguments:\n" + 246 "FileRW.loadFileToVector(\"" + f + "\", " + includeNewLine + ");" 247 ); 248 } 249 250 throw new UnreachableError(); // Should NOT be possible to reach this statement... 251 } 252 253 254 /** 255 * This loads a file to a {@code Vector} of {@code String's}. It halts the program, and prints 256 * a detailed message if any {@code Error's} or {@code Exception's} occur. The directory inside 257 * the jar-file where this file may be located identified by parameter 258 * {@code 'classLoaderClass'}. 259 * 260 * @param classLoaderClass <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_CLASS_LOAD_C> 261 * <EMBED CLASS='external-html' DATA-FILE-ID=RAWTYPES> 262 * 263 * @param f This is a {@code String} that contains the filename of the data-file that needs to 264 * be loaded. It is a 'relative file-name' that is relative to the jar-file / directory pair 265 * location that the class loader identifies using the {@code Class} from parameter 266 * {@code 'classLoaderClass'}. 267 * 268 * @param includeNewLine States whether the {@code '\n'} (newline) character should be appended 269 * to each element of the {@code Vector}. 270 * 271 * @return a {@code Vector} of {@code String's}, where each element in the {@code Vector} is a 272 * line retrieved from the text-file. 273 * 274 * @see #ERROR_EXIT(Throwable, String) 275 */ 276 public static Vector<String> loadFileToVector_JAR 277 (Class<?> classLoaderClass, String f, boolean includeNewLine) 278 { 279 // These are 'java.lang.AutoCloseable', and java handles them automatically 280 // if there is an exception 281 282 try ( 283 InputStream is = classLoaderClass.getResourceAsStream(f); 284 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 285 ) 286 { 287 String s = ""; 288 Vector<String> ret = new Vector<>(); 289 290 if (includeNewLine) 291 while ((s = br.readLine()) != null) 292 ret.addElement(s + '\n'); 293 294 else 295 while ((s = br.readLine()) != null) 296 ret.addElement(s); 297 298 return ret; 299 } 300 301 catch (Throwable t) 302 { 303 ERROR_EXIT( 304 t, 305 "Error loading text-file [" + f + "] from jar-file.\n" + 306 "Parameter includeNewLine was: " + includeNewLine + "\n" + 307 "Class loader attempted to use information in class " + 308 "[" + classLoaderClass.getCanonicalName() + "], but failed." 309 ); 310 } 311 312 throw new UnreachableError(); // Should NOT be possible to reach this statement... 313 } 314 315 /** 316 * This loads a {@code java.lang.Object} from a data-file. 317 * <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_CONTAINER> 318 * 319 * @param f The name of the file containing a serialized {@code java.lang.Object} to load 320 * 321 * @param zip This should be <I>TRUE</I> if, when serialized, the {@code Object} was compressed 322 * too, and <I>FALSE</I> if compression was not used. 323 * 324 * @param returnClass <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_RET_CLASS> 325 * 326 * @param <T> This type parameter is simply provided for convenience, to allow the user to 327 * specify the return class, without having to cast the object and suppress warnings, or catch 328 * exceptions. 329 * 330 * @return A de-serialized {@code java.lang.Object} present in the data-file passed by-name 331 * through file-name parameter {@code 'f'}, and cast to the type denoted by parameter 332 * {@code returnClass}. 333 * 334 * @see FileRW#readObjectFromFile(String, boolean) 335 * @see #ERROR_EXIT(Throwable, String) 336 */ 337 public static <T> T readObjectFromFile(String f, boolean zip, Class<T> returnClass) 338 { 339 try 340 { 341 Object ret = FileRW.readObjectFromFile(f, zip); 342 343 if (! returnClass.isInstance(ret)) 344 345 ERROR_EXIT( 346 "Serialized Object from file: " + f + "\n" + 347 "Using expected (" + (zip ? "zip-compression" : "no-compression") + ")\n" + 348 "Didn't have an object with class-name: [" + returnClass + "]\n" + 349 "but rather with class-name: [" + ret.getClass().getName() + "]" 350 ); 351 352 return returnClass.cast(ret); 353 } 354 355 catch (Throwable t) 356 { 357 ERROR_EXIT( 358 t, 359 "Exception reading Serialized Object from file: " + f + "\n" + 360 "With intended read class-name of: " + returnClass + "\n" + 361 "Using expected (" + (zip ? "zip-compression" : "no-compression") + ")\n" 362 ); 363 } 364 365 throw new UnreachableError(); // Should NOT be possible to reach this statement... 366 } 367 368 /** 369 * This loads a {@code java.lang.Object} from a data-file located in a JAR File. 370 * <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_CONTAINER> 371 * 372 * @param classLoaderClass <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_CLASS_LOAD_C> 373 * <EMBED CLASS='external-html' DATA-FILE-ID=RAWTYPES> 374 * 375 * @param f The name of the file containing a serialized {@code java.lang.Object} to load 376 * 377 * @param zip This should be <I>TRUE</I> if, when serialized, the {@code Object} was compressed 378 * too, and <I>FALSE</I> if compression was not used. 379 * 380 * @param returnClass <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_RET_CLASS> 381 * 382 * @param <T> This type parameter is simply provided for convenience, to allow the user to 383 * specify the return class, without having to cast the object and suppress warnings, or catch 384 * exceptions. 385 * 386 * @return a de-serialized {@code java.lang.Object} present in the data-file passed by-name 387 * through file-name parameter {@code 'f'}, and cast to the type denoted by parameter 388 * {@code 'returnClass'}. 389 * 390 * @see #ERROR_EXIT(Throwable, String) 391 */ 392 public static <T> T readObjectFromFile_JAR 393 (Class<?> classLoaderClass, String f, boolean zip, Class<T> returnClass) 394 { 395 // These are 'java.lang.AutoCloseable', and java handles them automatically 396 // if there is an exception 397 398 try ( 399 InputStream is = classLoaderClass.getResourceAsStream(f); 400 401 // The user may or may not have asked for reading a *COMPRESSED* file 402 ObjectInputStream ois = zip 403 ? new ObjectInputStream(new GZIPInputStream(is)) 404 : new ObjectInputStream(is); 405 ) 406 { 407 Object ret = ois.readObject(); 408 409 if (! returnClass.isInstance(ret)) ERROR_EXIT( 410 "Serialized Object from jar-file loading-using class: " + 411 classLoaderClass.getCanonicalName() + "\n" + 412 "Looking for data-file named: " + f + "\n" + 413 "Using expected (" + (zip ? "zip-compression" : "no-compression") + ")\n" + 414 "Didn't have an object with class-name: [" + returnClass + "]\n" + 415 "but rather with class-name: [" + ret.getClass().getName() + "]" 416 ); 417 418 return returnClass.cast(ret); 419 } 420 421 catch (Throwable t) 422 { 423 ERROR_EXIT( 424 t, 425 "Exception reading Serialized Object from jar-file, loading-using class: " + 426 classLoaderClass.getCanonicalName() + "\n" + 427 "Looking for data-file named: " + f + "\n" + 428 "And attempting to retrieve an object having class-name: " + returnClass + "\n" + 429 "Using expected (" + (zip ? "zip-compression" : "no-compression") + ")\n" 430 ); 431 432 throw new UnreachableError(); // Should NOT be possible to reach this statement... 433 } 434 } 435 436 437 // ******************************************************************************************** 438 // ******************************************************************************************** 439 // Google Cloud Server - Public Static Inner Class 440 // ******************************************************************************************** 441 // ******************************************************************************************** 442 443 444 /** 445 * The Google Cloud Server Storage Bucket extension of "Load File Exception Catch" does the 446 * work that <CODE>LFEC</CODE> does, but for GCS Storage Buckets, rather than operating 447 * system files. 448 * 449 * <EMBED CLASS='external-html' DATA-FILE-ID=LFEC_GCSSB> 450 */ 451 @Torello.JavaDoc.StaticFunctional 452 public static class GCSSB 453 { 454 private GCSSB() { } 455 456 /** 457 * This will read a Java Serialized {@code java.lang.Object} from a location in a Google 458 * Cloud Server {@code Storage Bucket}. 459 * 460 * @param storage <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_STORAGE> 461 * 462 * @param bucket The {@code bucket} name of the {@code bucket} from a Google Cloud Server 463 * account. 464 * 465 * @param completeFileName <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_CMPL_FNAME> 466 * 467 * @param zip <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_ZIP> 468 * 469 * @param returnClass This is the type expected to be found by Java in the Serialized 470 * {@code Object} Data-File. If an {@code Object} is read from this location, but it does 471 * not have the type indicated by this parameter, the program will also halt, and an 472 * explanatory exception message will be printed to the console/terminal. 473 * 474 * @param <T> This type parameter is simply provided for convenience, to allow the user 475 * to specify the return class, without having to cast the object and suppress warnings, 476 * or catch exceptions. 477 * 478 * @return A de-serialized java {@code java.lang.Object} that has been read from a GCS 479 * {@code Storage Bucket}, and cast to the type denoted by parameter 480 * {@code 'returnClass'}. 481 * 482 * @see FileRW#readObjectFromFile(String, boolean) 483 * @see FileRW#readObjectFromFileNOCNFE(String, boolean) 484 * @see #readObjectFromFile(String, boolean, Class) 485 * @see #ERROR_EXIT(String) 486 */ 487 public static <T> T readObjectFromFile( 488 Storage storage, String bucket, String completeFileName, 489 boolean zip, Class<T> returnClass 490 ) 491 { 492 try 493 { 494 // Read Storage Bucket Data into a byte[] array 495 byte[] bArr = storage.get(bucket, completeFileName).getContent(); 496 497 // Build an Input Stream, using that byte[] array as input 498 ByteArrayInputStream bis = new ByteArrayInputStream(bArr); 499 500 // Build an Object Input Stream, using the byte-array input-stream as input 501 ObjectInputStream ois = zip 502 ? new ObjectInputStream(new GZIPInputStream(bis)) 503 : new ObjectInputStream(bis); 504 505 // Use Java's Object Serialization method to read the Object 506 Object ret = ois.readObject(); 507 508 if (! returnClass.isInstance(ret)) ERROR_EXIT( 509 "Serialized Object read from GCS Storage Bucket: " + bucket + "\n" + 510 "And file-name: " + completeFileName + "\n" + 511 "Using expected (" + (zip ? "zip-compression" : "no-compression") + ")\n" + 512 "Didn't have an object with class-name: " + returnClass + "\n" + 513 "But rather with className: " + ret.getClass().getName() 514 ); 515 516 ois.close(); bis.close(); 517 518 return returnClass.cast(ret); 519 } 520 521 catch (Throwable t) 522 { 523 ERROR_EXIT( 524 t, 525 "Serialized Object read from GCS Storage Bucket: " + bucket + "\n" + 526 "And file-name: " + completeFileName + "\n" + 527 "Using expected (" + (zip ? "zip-compression" : "no-compression") + ")\n" + 528 "And Expected class-name: " + returnClass + "\n" 529 ); 530 531 throw new UnreachableError(); // Cannot reach this statement 532 } 533 } 534 535 /** 536 * This merely loads a text-file from Google's Storage Bucket infrastructure into a 537 * {@code String.} Make sure to check that the file you are loading does indeed have 538 * text-content. 539 * 540 * @param storage <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_STORAGE> 541 * 542 * @param bucket The {@code bucket} name of the {@code bucket} from a Google Cloud Server 543 * account. 544 * 545 * @param completeFileName <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_CMPL_FNAME> 546 * 547 * @return The text file on Google Cloud Server's Storage Bucket file/directory returned as 548 * a {@code java.lang.String} 549 */ 550 public static String loadFileToString 551 (Storage storage, String bucket, String completeFileName) 552 { return new String(storage.get(bucket, completeFileName).getContent()); } 553 554 /** 555 * This merely loads a text-file from Google's Storage Bucket infrastructure into a 556 * {@code String}. Make sure to check that the file you are loading does indeed have 557 * text-content. 558 * 559 * @param storage <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_STORAGE> 560 * 561 * @param bucket The {@code bucket} name of the {@code bucket} from a Google Cloud Server 562 * account. 563 * 564 * @param completeFileName <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_CMPL_FNAME> 565 * 566 * @param includeNewLine This tells the method to include, or not-include, a {@code '\n'} 567 * (newline) character to each {@code String}. 568 * 569 * @return The text file on Google Cloud Server's {@code Storage Bucket} file/directory 570 * stuff as a {@code Vector} of {@code String's}. 571 * 572 * @see #loadFileToString(Storage, String, String) 573 */ 574 public static Vector<String> loadFileToVector 575 (Storage storage, String bucket, String completeFileName, boolean includeNewLine) 576 { 577 String s = loadFileToString(storage, bucket, completeFileName); 578 Vector<String> ret = new Vector<>(); 579 580 int pos = 0; 581 int delta = includeNewLine ? 1 : 0; 582 int lastPos = 0; 583 584 while ((pos = s.indexOf('\n')) != -1) 585 { 586 ret.add(s.substring(lastPos, pos + delta)); 587 lastPos = pos + 1; 588 } 589 590 if (lastPos < s.length()) ret.add(s.substring(lastPos)); 591 592 return ret; 593 } 594 595 /** 596 * This will write the contents of a java {@code 'CharSequence'} - includes 597 * {@code String, StringBuffer & StringBuilder} to a 598 * file on Google Cloud Server's storage bucket system. 599 * 600 * @param storage <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_STORAGE> 601 * 602 * @param bucket The {@code bucket} name of the {@code bucket} from a Google Cloud Server 603 * account. 604 * @param completeFileName <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_CMPL_FNAME> 605 * 606 * @param ASCIIorUTF8 When writing java {@code String's} the file-system, it is generally 607 * not to important to worry about whether java has stored an {@code 'ASCII'} encoded 608 * {@code String}, or a {@code String} encoded using {@code 'UTF-8'}. Most 609 * foreign-language news-sites require the latter ({@code 'UTF-8'}), but any site that is 610 * strictly English can get by with plain old ASCII. 611 * 612 * <BR /><BR /><B><SPAN STYLE="color: red">IMPORTANT:</B></SPAN> When this boolean is 613 * {@code TRUE}, this method will attempt to presume the character-sequence you have passed 614 * is in ASCII, and write it that way. When this boolean is set to {@code FALSE}, 615 * this method will attempt to write the {@code String} of {@code byte's} as a 616 * {@code 'UTF-8'} encoded character-set. 617 * 618 * <BR /><BR /><B>ALSO:</B> I have not made any allowance for Unicode or Unicode little 619 * endian, because I have never used them with either the Chinese or Spanish sites I 620 * scrape. UTF-8 has been the only other character set I encounter. 621 */ 622 public static void writeFile( 623 CharSequence fileAsStr, Storage storage, String bucket, 624 String completeFileName, boolean ASCIIorUTF8 625 ) 626 { 627 BlobInfo blobInfo = BlobInfo.newBuilder 628 (BlobId.of(bucket, completeFileName)).setContentType("text/plain").build(); 629 630 byte[] file = ASCIIorUTF8 631 ? fileAsStr.toString().getBytes() 632 : fileAsStr.toString().getBytes(java.nio.charset.Charset.forName("UTF-8")); 633 634 Blob blob = storage.create(blobInfo, file); 635 } 636 637 /** 638 * This will write a Java {@code Serializable Object} to a location in a Google Cloud 639 * Server Storage Bucket. 640 * 641 * @param storage <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_STORAGE> 642 * 643 * @param o This may be any {@code Serializable Java Object}. {@code Serializable Java 644 * Objects} are ones which implement the {@code interface java.io.Serializable}. 645 * 646 * @param bucket The {@code bucket} name of the {@code bucket} from a Google Cloud Server 647 * account. 648 * 649 * @param completeFileName <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_CMPL_FNAME> 650 * 651 * @param zip <EMBED CLASS='external-html' DATA-FILE-ID=GCSSB_ZIP> 652 */ 653 public static void writeObjectToFile( 654 Object o, Storage storage, String bucket, 655 String completeFileName, boolean zip 656 ) 657 throws IOException 658 { 659 // Retrieves a file-name object using a GCS BUCKET-NAME, and the FILE-NAME (in 660 // the bucket) 661 662 BlobId blobId = BlobId.of(bucket, completeFileName); 663 664 // This BlobInfo is GCS version of "java.io.File". It points to a specific file 665 // inside a GCS Bucket (which was specified earlier) 666 667 BlobInfo blobInfo = BlobInfo 668 .newBuilder(blobId) 669 // .setContentType("text/plain") 670 .build(); 671 672 // This will save the Serialized Object Data to a Stream (and eventually an array) 673 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 674 675 // This stream writes serialized Java-Objects to the Storage Bucket 676 ObjectOutputStream oos = zip 677 ? new ObjectOutputStream(new GZIPOutputStream(baos)) 678 : new ObjectOutputStream(baos); 679 680 oos.writeObject(o); 681 682 oos.flush(); baos.flush(); oos.close(); 683 684 // Convert that BAOS to a Byte-Array 685 byte[] bArr = baos.toByteArray(); 686 687 // Write the BYTE-ARRAY to the GCS Bucket and file using the "BlobInfo" that was built 688 // a few lines ago. 689 690 Blob blob = storage.create(blobInfo, bArr); 691 } 692 } 693}