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