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