001package Torello.JavaDoc; 002 003import Torello.Java.*; 004import Torello.HTML.*; 005import Torello.JDUInternal.DataClasses.ClassUpgradeData.*; 006import Torello.JDUInternal.Throwables.*; 007 008import static Torello.Java.C.*; 009 010import Torello.JDUInternal.GeneralPurpose.Messager; 011import Torello.JDUInternal.GeneralPurpose.MessagerVerbose; 012 013import Torello.JDUInternal.JDU_MAIN.*; 014 015import Torello.JDUInternal.HTMLProcessors.Other.LinksChecker; 016 017import Torello.JDUInternal.UserConfigReaders.RetrieveEmbedTagMapPropFiles; 018 019import Torello.Java.HiLiteMe.Cache; 020import Torello.HTML.Tools.Images.IF; 021 022import Torello.Java.ReadOnly.ReadOnlyMap; 023import Torello.Java.ReadOnly.ReadOnlyList; 024import Torello.Java.ReadOnly.ReadOnlyArrayList; 025 026import Torello.Java.Build.BuildPackage; 027 028import java.util.*; 029import java.io.*; 030import java.util.stream.*; 031import java.util.function.*; 032 033 034/** 035 * The primary builder and configuration class for the Java Doc Upgrade Process, having many 036 * customizations that may be requested using the customize-settings methods available here. 037 * 038 * <EMBED CLASS='external-html' DATA-FILE-ID=UPGRADE> 039 */ 040public class Upgrade 041{ 042 // ******************************************************************************************** 043 // ******************************************************************************************** 044 // Public-Static Constant/Final Fields 045 // ******************************************************************************************** 046 // ******************************************************************************************** 047 048 049 /** The name of the favicon-file (without extension). This filename may not be changed. */ 050 public static final String FAVICON_FILE_NAME = "favicon"; 051 052 /** The name of the (very brief) {@code '.js'} file. */ 053 public static final String JAVA_SCRIPT_FILE_NAME = "JDU.js"; 054 055 056 // ******************************************************************************************** 057 // ******************************************************************************************** 058 // Private Fields (all are final/Constants - except "Stats") 059 // ******************************************************************************************** 060 // ******************************************************************************************** 061 062 063 // These are acctually for Internal-Use, and shouldn't be public. Unfortunately due to Java's 064 // leaving out the 'friend' key-word from C/C++, these have to be public in order to share them 065 // with the Internal-Only Packages in JavaDoc-Upgrader. 066 067 private final UpgradePredicates.Builder predicatesBuilder = new UpgradePredicates.Builder(); 068 private final UpgradeSettings.Builder settingsBuilder = new UpgradeSettings.Builder(); 069 private final PathsAndTypes.Builder pathsTypesBuilder = new PathsAndTypes.Builder(); 070 071 // Used by the log-file header string below 072 private final String dateTimeStr = 073 StringParse.dateStr('-') + " " + StringParse.timeStr(':'); 074 075 // Prepended to the log-file that may (or may not) be saved to disk, or an Appendable 076 private final String logFileHeader = 077 "<HTML>\n<HEAD>\n" + 078 "<TITLE>Log " + dateTimeStr + "</TITLE>\n" + 079 "<STYLE type='text/css'>\n" + C.getCSSDefinitions() + "\n</STYLE>\n" + 080 "</HEAD>\n" + 081 "<BODY STYLE='margin: 1em; background: black; color: white;'>\n\n" + 082 "<H1>JavaDoc Upgrader Log</H1>\n" + 083 "<CODE>" + dateTimeStr + "</CODE>\n" + 084 "<PRE>\n\n"; 085 086 // used internally 087 private static final TextNode NEWLINE = new TextNode("\n"); 088 089 // NOTE: This isn't final.... It can be re-constructed in this class.... 090 private Stats stats = new Stats(); 091 092 093 // ******************************************************************************************** 094 // ******************************************************************************************** 095 // Building / Constructor, Running the Upgrader 096 // ******************************************************************************************** 097 // ******************************************************************************************** 098 099 100 /** 101 * This returns a new instance of this class. It will have all empty and null settings, except 102 * the root-directory descriptors. It must be initialized with the various builder methods. 103 * 104 * <BR /><BR /> 105 * This constructor must tell the Upgrader (Builder) which directory contains {@code '.java'} 106 * Source-Files, and which directory shall contain Java-Doc Generated HTML Documentation Pages. 107 * 108 * @param rootJavaDocDirectory This is the output directory that was used for the last call to 109 * the JavaDoc Utility. The Upgrade Logic should expect to find all class, interface and 110 * enumerated types to be hilited in this directory. This parameter may not be null. 111 * 112 * @param rootSourceFileDirectories This is the location where the {@code '.java'} source files 113 * for the classes, interfaces and enumerated types named by your list files are stored. This 114 * parameter may not be null; at least one directory must be passed. If you have multiple 115 * source-code directories, then pass all of them, and whenever a JavaDoc {@code '.html'} file 116 * is loaded from disk, all source-code directories will be searched until the source-code is 117 * found. 118 * 119 * @throws UpgradeException This exception will throw if either of these directories cannot be 120 * found, or may not be accessed. The {@code 'getCause()'} method of the exception will 121 * provide more details of the specific error that occurred. 122 */ 123 public Upgrade(String rootJavaDocDirectory, String... rootSourceFileDirectories) 124 { 125 // System.out.println("rootJavaDocDirectory = [" + rootJavaDocDirectory + "]\n" + 126 // "rootSourceFileDirectory = [" + rootSourceFileDirectory + "]"); 127 128 Objects.requireNonNull( 129 rootJavaDocDirectory, 130 "You have passed 'null' to parameter 'rootJavaDocDirectory'" 131 ); 132 133 Objects.requireNonNull( 134 rootSourceFileDirectories, 135 "You have passed 'null' to parameter 'rootSourceFileDirectories'" 136 ); 137 138 // NOTE: Java seems to have no problem with '.' and '..' inside of a File-Name 139 if (StrCmpr.containsOR(rootJavaDocDirectory, "*", "?")) 140 141 throw new UpgradeException( 142 "The Root JavaDoc Directory String you have passed contains either the '*' " + 143 "character, or the '?', but these is not allowed." 144 ); 145 146 // Check for these errors inside the Root Source Directories too. 147 for (String s : rootSourceFileDirectories) if (StrCmpr.containsOR(s, "*", "?")) 148 149 throw new UpgradeException( 150 "One of the Root Source Directory Strings that you have passed contains either " + 151 "the '*' character, or the '?', but these is not allowed." 152 ); 153 154 if (rootSourceFileDirectories.length == 0) throw new UpgradeException( 155 "You have not passed any source-code directories to parameter " + 156 "'rootSourceFileDirectories'" 157 ); 158 159 /* 160 // THIS HAS TO BE MOVED / COPIED 161 if (rootJavaDocDirectory.length() > 0) 162 UpgradeException.checkFileExistsAndCanAccess 163 (rootJavaDocDirectory, "Root '.html' Java-Doc Documentation Page Directory"); 164 */ 165 166 for (String rootSourceDir : rootSourceFileDirectories) 167 if (rootSourceDir.length() > 0) 168 UpgradeException.checkFileExistsAndCanAccess 169 (rootSourceDir, "Root '.java' Source File Directory"); 170 171 // Easier to type "rsd" in the code below 172 String[] rsd = new String[rootSourceFileDirectories.length]; 173 174 175 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 176 // Ensure File.separator is at the end of each of these directory-names - except dir "" 177 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 178 // 179 // If the directory is the "Current Working Directory" - which is specified by the 180 // Zero-Length-String (a.k.a ""), then a trailing File.separator should **NOT** be added. 181 // All other directory names must end with the File.separator 182 // 183 // NOTE: For checking that a directory exists and can be accessed (the previous lines of 184 // code), the class java.io.File doesn't require that there be a trailing File 185 // Separator. However, in this package (the JD-Upgrader Package), appending file 186 // names to these root-directories mandates that the File-Separator be present at the 187 // end of each of these directory-names - except, of course, the "" directory - which 188 // is the "Current Working Directory." 189 // 190 // SPECIFICALLY: Later on when these Upgrade-Fields are actually used by the class 191 // "MainFilesProcessor" - making sure these directory-names end with '/' is 192 // where this stuff actually comes into play 193 194 for (int i=0; i < rootSourceFileDirectories.length; i++) 195 196 // DON'T FORGET: This *DOES NOT* end with File.separator - but it doesn't have to! 197 if (rootSourceFileDirectories[i].length() == 0) 198 rsd[i] = ""; 199 200 else if (rootSourceFileDirectories[i].endsWith(File.separator)) 201 rsd[i] = rootSourceFileDirectories[i]; 202 203 else 204 rsd[i] = rootSourceFileDirectories[i] + File.separator; 205 206 // if (rsd == null) System.out.println("rsd is null!!!"); 207 // else System.out.println(Arrays.toString(rsd)); 208 this.pathsTypesBuilder.rootSourceFileDirectories = ReadOnlyList.of(rsd); 209 210 211 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 212 // Make sure the File.separator is here too, unless Root-JD-Dir is the CWD (the "" dir) 213 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 214 215 // This *DOES NOT* end with File.separator - but it doesn't have to! 216 if (rootJavaDocDirectory.length() == 0) 217 this.pathsTypesBuilder.rootJavaDocDirectory = ""; 218 219 else if (rootJavaDocDirectory.endsWith(File.separator)) 220 this.pathsTypesBuilder.rootJavaDocDirectory = rootJavaDocDirectory; 221 222 else 223 this.pathsTypesBuilder.rootJavaDocDirectory = rootJavaDocDirectory + File.separator; 224 } 225 226 /** 227 * <EMBED CLASS='external-html' DATA-FILE-ID=U_UPGRADE> 228 * 229 * @return This returns the statistics computed for the upgrade process. See class 230 * {@link Stats} for more information. A complete listing of the information contained by 231 * the tables in a {@code 'Stats'} instance may be viewed by clicking the {@code 'Stats'} 232 * link at the top-right of this page. 233 * 234 * <BR /><BR />If the Upgrade-Process had unrecoverable errors, null is returned. 235 */ 236 public Stats upgrade() 237 { 238 if (this.pathsTypesBuilder.rootJavaDocDirectory.length() > 0) 239 240 UpgradeException.checkFileExistsAndCanAccess( 241 this.pathsTypesBuilder.rootJavaDocDirectory, 242 "Root '.html' Java-Doc Documentation Page Directory" 243 ); 244 245 final UpgradePredicates predicates = this.predicatesBuilder.build(); 246 final UpgradeSettings settings = this.settingsBuilder.build(); 247 248 try 249 { 250 Preliminaries.run(settings, pathsTypesBuilder); 251 252 final PathsAndTypes pathsTypes = this.pathsTypesBuilder.build(); 253 254 if (Messager.hadErrors()) return null; 255 256 LoopJavaPackages.run(predicates, settings, pathsTypes, stats); 257 258 if (Messager.hadErrors()) return null; 259 260 this.stats.saveStatsHTMLFile(pathsTypes.rootJavaDocDirectory); 261 } 262 263 catch (ReachedMaxErrors rme) 264 { System.out.println("Reached Maximum Number of Errors. Exiting"); return null; } 265 266 // Currently Ignoring: HiLiteException 267 catch (JavaDocError | HiLiteError | ParseException | UpgradeException e) 268 { 269 System.out.println(e.getClass().getSimpleName() + " thrown. Exiting.\n"); 270 return null; 271 } 272 273 catch (Throwable t) 274 { 275 System.out.println( 276 '\n' + 277 "****************************************************************\n" + 278 EXCC.toString(t) + 279 "****************************************************************\n" + 280 "Unexpected Throw, Exiting." 281 ); 282 283 return null; 284 } 285 286 finally 287 { 288 if (this.settingsBuilder.hlmCache != null) 289 this.settingsBuilder.hlmCache.persistMasterHashToDisk(); 290 } 291 292 if (settings.linksChecker != null) settings.linksChecker.runCheck(); 293 294 return this.stats; // Perhaps this is useful to the end-user, perhaps not. 295 } 296 297 /** 298 * <EMBED CLASS='external-html' DATA-FILE-ID=U_MAIN> 299 * @param argv This is the argument received from the command line. 300 */ 301 public static void main(String[] argv) throws Exception 302 { 303 Upgrade upgrader = new Upgrade(argv[0], ""); 304 305 if (argv.length == 1) upgrader.upgrade(); 306 307 else if (argv.length == 2) 308 { 309 java.io.File f = new java.io.File(argv[1]); 310 311 if (! f.exists()) 312 { 313 f.mkdirs(); 314 Cache.initializeOrClear(argv[1], null); 315 } 316 317 Cache CACHE = new Cache(argv[1]); 318 upgrader.useHiLiteServerCache(CACHE).upgrade(); 319 CACHE.persistMasterHashToDisk(); 320 } 321 322 else System.out.println("Failed, expected one or two arguments"); 323 } 324 325 326 // ******************************************************************************************** 327 // ******************************************************************************************** 328 // Filter-Predicates 329 // ******************************************************************************************** 330 // ******************************************************************************************** 331 332 333 /** Write an explanation*/ 334 @SuppressWarnings("unchecked") 335 public Upgrade setRemoveAllDetailsFilter(Predicate<? super String> cietCanonicalNameFilter) 336 { 337 this.predicatesBuilder.removeAllDetailsFilter = 338 (Predicate<String>) cietCanonicalNameFilter; 339 340 return this; 341 } 342 343 /** 344 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_REM_ALL_DET_F> 345 * @param entity Specifies which HTML Detail-Section to remove. 346 * @param cietCanonicalNameFilter <EMBED CLASS='external-html' DATA-FILE-ID=U_CCNF> 347 */ 348 public Upgrade setRemoveAllDetailsFilter 349 (Entity entity, Predicate<? super String> cietCanonicalNameFilter) 350 { 351 @SuppressWarnings("unchecked") 352 Predicate<String> p = (Predicate<String>) cietCanonicalNameFilter; 353 354 switch (Objects.requireNonNull(entity)) 355 { 356 case METHOD: 357 this.predicatesBuilder.removeAllMethodDetailsFilter = p; 358 return this; 359 360 case CONSTRUCTOR: 361 this.predicatesBuilder.removeAllConstructorDetailsFilter = p; 362 return this; 363 364 case FIELD: 365 this.predicatesBuilder.removeAllFieldDetailsFilter = p; 366 return this; 367 368 case ENUM_CONSTANT: 369 this.predicatesBuilder.removeAllECDetailsFilter = p; 370 return this; 371 372 case ANNOTATION_ELEM: 373 this.predicatesBuilder.removeAllAEDetailsFilter = p; 374 return this; 375 376 case INNER_CLASS: 377 throw new IllegalArgumentException( 378 "You have passed Entity.INNER_CLASS to parameter 'entity', but JavaDoc HTML " + 379 "Web-Pages do not have a Nested-Type / Inner-Class Details-Section to remove " + 380 "in the first place." 381 ); 382 383 default: throw new UnreachableError(); 384 } 385 } 386 387 /** 388 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_HL_ALL_DET_F> 389 * @param cietCanonicalNameFilter <EMBED CLASS='external-html' DATA-FILE-ID=U_CCNF> 390 */ 391 public Upgrade setHiLiteAllDetailsFilter 392 (Entity entity, Predicate<? super String> cietCanonicalNameFilter) 393 { 394 @SuppressWarnings("unchecked") 395 Predicate<String> p = (Predicate<String>) cietCanonicalNameFilter; 396 397 switch(Objects.requireNonNull(entity)) 398 { 399 case METHOD: 400 this.predicatesBuilder.hiLiteAllMethodsFilter = p; 401 return this; 402 403 case CONSTRUCTOR: 404 this.predicatesBuilder.hiLiteAllConstructorsFilter = p; 405 return this; 406 407 case FIELD: 408 this.predicatesBuilder.hiLiteAllFieldsFilter = p; 409 return this; 410 411 case ENUM_CONSTANT: 412 this.predicatesBuilder.hiLiteAllECsFilter = p; 413 return this; 414 415 case ANNOTATION_ELEM: 416 this.predicatesBuilder.hiLiteAllAEsFilter = p; 417 return this; 418 419 case INNER_CLASS: 420 throw new IllegalArgumentException(); 421 422 default: throw new UnreachableError(); 423 } 424 } 425 426 /** 427 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_SUMM_REM_F> 428 * @param cietCanonicalNameFilter <EMBED CLASS='external-html' DATA-FILE-ID=U_CCNF> 429 */ 430 @SuppressWarnings("unchecked") 431 public Upgrade setSummaryRemoveFilter(Predicate<? super String> cietCanonicalNameFilter) 432 { 433 this.predicatesBuilder.summaryRemoveFilter = (Predicate<String>) cietCanonicalNameFilter; 434 return this; 435 } 436 437 /** 438 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_HL_SCF_F> 439 * @param cietCanonicalNameFilter <EMBED CLASS='external-html' DATA-FILE-ID=U_CCNF> 440 */ 441 @SuppressWarnings("unchecked") 442 public Upgrade setHiLiteSourceCodeFileFilter(Predicate<? super String> cietCanonicalNameFilter) 443 { 444 this.predicatesBuilder.hiLiteSourceCodeFileFilter = 445 (Predicate<String>) cietCanonicalNameFilter; 446 447 return this; 448 } 449 450 /** 451 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_CSS_TAGS_F> 452 * @param cietCanonicalNameFilter <EMBED CLASS='external-html' DATA-FILE-ID=U_CCNF> 453 */ 454 @SuppressWarnings("unchecked") 455 public Upgrade setCSSTagsFilter(Predicate<? super String> cietCanonicalNameFilter) 456 { 457 this.predicatesBuilder.cssTagsFilter = (Predicate<String>) cietCanonicalNameFilter; 458 return this; 459 } 460 461 /** 462 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_VAL_HTML_F> 463 * @param cietCanonicalNameFilter <EMBED CLASS='external-html' DATA-FILE-ID=U_CCNF> 464 */ 465 @SuppressWarnings("unchecked") 466 public Upgrade setValidateHTMLFilter(Predicate<? super String> cietCanonicalNameFilter) 467 { 468 this.predicatesBuilder.validateHTMLFilter = (Predicate<String>) cietCanonicalNameFilter; 469 return this; 470 } 471 472 473 // ******************************************************************************************** 474 // ******************************************************************************************** 475 // Setting Features: Output Printing and Log-File 476 // ******************************************************************************************** 477 // ******************************************************************************************** 478 479 480 /** 481 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_VERBOSITY_LVL> 482 * @param verbosity One of the four available {@link Verbosity} constants. 483 */ 484 public Upgrade setVerbosityLevel(Verbosity verbosity) 485 { 486 this.settingsBuilder.verbosityLevel = verbosity.level; 487 Messager.setVerbosityLevel(verbosity.level); 488 if (verbosity.level == 3) MessagerVerbose.setVerbose(); 489 return this; 490 } 491 492 /** 493 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_LOG_FILE_APND> 494 * @param logFile An {@code Appendable} to be used for backing-up / saving Log-Writes. 495 */ 496 public Upgrade setLogFile(Appendable logFile) 497 { 498 this.settingsBuilder.logFile = logFile; 499 Messager.setLogAppendable(logFile); 500 501 return this; 502 } 503 504 /** 505 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_LOG_FILE_FN> 506 * @param logFileName File-Name of a writeable File, to be used for backuping-up Log-Writes 507 * @throws UpgradeException If the File provided cannot be written to. 508 * @see UpgradeException#checkFileIsWriteable(String, String, String) 509 */ 510 public Upgrade setLogFile(String logFileName) 511 { 512 // This is just used / passed to the "Exception Checker" (below) to build a more 513 // readable Exception-Message. 514 515 String fileDescription = "Disk / File-System Upgrader Log-Dump File"; 516 517 // Write log-file header. Check that the log-file is accessible and writable. 518 UpgradeException.checkFileIsWriteable(logFileName, fileDescription, logFileHeader); 519 520 // Build a java.util.function.Consumer<String> 521 // This consumer will function as the log-file write-mechanism. 522 523 this.settingsBuilder.logFile = new Appendable() 524 { 525 // This method is never actually used by the log-writes in JD-Upgrader. Realize that 526 // writing to the log, and actually check-pointing the log to disk are not the same 527 // thing. This appendable is used for actually writing out the log contents to a 528 // flat-file (or any user-provided output/storing mechanism that the user can think of) 529 // 530 // The user has the option of writing the log-contents to some other, user-specified, 531 // appendable that does whatever it wants with the log-contents. 532 // 533 // But whatever it is! - Check-pointing the log to it's output is only done in the 534 // class Messager - using the method: Messager.checkPointLog(); 535 // 536 // FURTHERMORE: The method "Messager.checkPointLog()" is only invoked twice! Once by 537 // the class "ExtraFilesProcessor" and once by "MainFilesProcessor" 538 539 public Appendable append(char c) // AGAIN: Not used 540 { throw new UnreachableError(); } 541 542 public Appendable append(CharSequence s, int start, int end) // NOT USED 543 { throw new UnreachableError(); } 544 545 // Invoked only once: In Messager.checkPointLog() 546 public Appendable append(CharSequence s) 547 { 548 try 549 { FileRW.appendToFile(s, logFileName); } 550 551 catch (IOException ioe) 552 { 553 throw new UpgradeException 554 ("Cannot write to log-file: [" + logFileName + "]", ioe); 555 } 556 557 return this; 558 } 559 }; 560 561 Messager.setLogAppendable(this.settingsBuilder.logFile); 562 563 return this; 564 } 565 566 567 // ******************************************************************************************** 568 // ******************************************************************************************** 569 // The HTML <EMBED> tag. These can be used to provide more processing to the user. 570 // ******************************************************************************************** 571 // ******************************************************************************************** 572 573 574 /** 575 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_EMBED_TAG_F> 576 * @param tagIDMapFileName A Java {@code '.properties'} File-Name mapping File-ID's to Files. 577 * @throws UpgradeException If there are any problems that occur while loading the file 578 */ 579 public Upgrade setProjectGlobalEmbedTagsMapFile(String tagIDMapFileName) 580 { 581 if (tagIDMapFileName == null) throw new UpgradeException 582 ("The parameter 'tagIDMapFileName' (as a String) was passed NULL."); 583 584 File tagIDMapFile = new File(tagIDMapFileName); 585 586 if (! tagIDMapFile.exists()) throw new UpgradeException 587 ("The <EMBED> Tag ID Map File Provided doesn't exist:\n[" + tagIDMapFileName + "]"); 588 589 if (! tagIDMapFile.isFile()) throw new UpgradeException 590 ("The <EMBED> Tag ID Map File Provided isn't a file:\n[" + tagIDMapFileName + "]"); 591 592 // MESSAGER: 593 // 1) INVOKES: println, assertFailGeneralPurpose 594 // 2) INVOKED-BY: MainFiesProcessor (main-loop, once), Upgrade (once) 595 // 3) RETURNS: Map<String, String> 596 // 4) THROWS: UpgradeException 597 598 ReadOnlyMap<String, String> tagIDMap = RetrieveEmbedTagMapPropFiles.readPropertiesFile 599 (tagIDMapFile); 600 601 if (tagIDMap == null) throw new UpgradeException 602 ("tagIDMapFileName: Could not Load.\n[" + tagIDMapFileName + "]"); 603 604 // NOTE: For "Project Global Tags Map" the "relative-directory" string is the empty 605 // String. (That is the empty-string parameter in the method call below) 606 // 607 // MESSAGER: 608 // 1) INVOKES: println, userErrorContinue (only non-throwing Messager methods) 609 // 2) INVOKED BY: Upgrade (twice), MainFilesProcessor (once) 610 // 3) RETURNS: TRUE ==> no errors, FALSE if there were any errors 611 // 4) THROWS: NO EXPLICIT THROWS STATEMENTS 612 613 Messager.setCurrentFileName(tagIDMapFileName, "<EMBED> Tag ID Map Properties File"); 614 615 boolean res = 616 RetrieveEmbedTagMapPropFiles.checkMap(tagIDMap, this.settingsBuilder.checkBalance, ""); 617 618 if (! res) throw new UpgradeException( 619 "There were errors when checking the HTML Validity of the External-HTML Global " + 620 "<EMBED> Tag Map '.properties' File:\n" + 621 " [" + tagIDMapFileName + "]" 622 ); 623 624 // Copy the Embed-Tag Map, (ID ==> FileName Map) into 'this' (internally-stored) map. 625 // this.settingsBuilder.projectGlobalEmbedTagsMap.clear(); 626 // this.settingsBuilder.projectGlobalEmbedTagsMap.putAll(tagIDMap); 627 628 this.settingsBuilder.projectGlobalEmbedTagsMap = tagIDMap; 629 630 631 // Register this with the 'Stats' class. This keeps a count of the use of each of these 632 // tags in Java Doc Pages, and outputs a 'Stats.html' file at the end. 633 634 this.stats = new Stats(this.settingsBuilder.projectGlobalEmbedTagsMap); 635 636 return this; 637 } 638 639 /** 640 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_EMBED_TAG_MAP> 641 * @param tagIDMap This should map a {@code 'DATA-FILE-ID'} to an {@code '.html'} File-Name 642 */ 643 public Upgrade setProjectGlobalEmbedTagsMap(ReadOnlyMap<String, String> tagIDMap) 644 { 645 if (tagIDMap == null) throw new UpgradeException 646 ("The parameter 'tagIDMap' (a java.util.Map<String, String>) was passed NULL."); 647 648 // This will check each line on the map, and log errors if there are errors 649 // 650 // NOTE: For "Project Global Tags Map" the "relative-directory" string is the empty 651 // String. (That is the empty-string parameter in the method call below) 652 // 653 // MESSAGER: 654 // 1) INVOKES: println, userErrorContinue (only non-throwing Messager methods) 655 // 2) INVOKED BY: Upgrade (twice), RetrieveEmbedTagMapPropFiles (once) 656 // 3) RETURNS: TRUE ==> no errors, FALSE if there were any errors 657 // 4) THROWS: NO EXPLICIT THROWS STATEMENTS 658 659 Messager.setCurrentFileName("User Provided Map Instance", "Instance, Not File"); 660 661 // This map is the "Project-Global" Tag-Map 662 boolean res = 663 RetrieveEmbedTagMapPropFiles.checkMap(tagIDMap, this.settingsBuilder.checkBalance, ""); 664 665 if (! res) throw new UpgradeException( 666 "There were errors when checking the HTML Validity of the External-HTML Global " + 667 "EMBED TAG FILES." 668 ); 669 670 // Copy the Embed-Tag Map, (ID ==> FileName Map) into 'this' (internally-stored) map. 671 // this.settingsBuilder.projectGlobalEmbedTagsMap.clear(); 672 // this.settingsBuilder.projectGlobalEmbedTagsMap.putAll(tagIDMap); 673 674 this.settingsBuilder.projectGlobalEmbedTagsMap = tagIDMap; 675 676 // Register this with the 'Stats' class. This keeps a count of the use of each of these 677 // tags in Java Doc Pages, and outputs a 'Stats.html' file at the end. 678 679 this.stats = new Stats(this.settingsBuilder.projectGlobalEmbedTagsMap); 680 681 // invocation chaining 682 return this; 683 } 684 685 686 // ******************************************************************************************** 687 // ******************************************************************************************** 688 // Using Features: The HiLiter & HiLiter-Cache 689 // ******************************************************************************************** 690 // ******************************************************************************************** 691 692 693 /** 694 * Convenience Method. 695 * <BR />Invokes: {@link HiLiter#getDefault(HiLiteMe.Cache, String, String)} 696 * <BR />And-Then: {@link #setHiLiter(HiLiter)} 697 */ 698 public Upgrade useHiLiteServerCache(HiLiteMe.Cache cache) 699 { 700 setHiLiter(HiLiter.getDefault(cache, "vim", "native")); 701 this.settingsBuilder.hlmCache = cache; 702 return this; 703 } 704 705 /** 706 * Configures the HiLiter to use the Default HiLiter, and use the provided Cache-Directory as 707 * the location for Caching HiLited HTML-Files. 708 * 709 * @param hiLiteServerCacheDirectoryName The name of the File-System Directory which has 710 * previously saved HiLited HTML-Files. 711 * 712 * <BR /><BR /><B STYLE='color: red;'>NOTE:</B> If this is the first time using this Cache 713 * Directory, and it doesn't exists yet, this directory will be created, and future 714 * {@code Upgrade} instances will save & cache HiLited-Source HTML to this directory. 715 */ 716 public Upgrade useHiLiteServerCache(String hiLiteServerCacheDirectoryName) 717 { 718 // These four lines allow the Upgrade Tool to cache results for documentation web-pages 719 // as they are hilited so that future builds will not have to "re-poll" the server when 720 // hiliting source-code files that have not changed. Use as depicted below. 721 722 final File f = new File(hiLiteServerCacheDirectoryName); 723 724 if (! f.exists()) 725 { 726 f.mkdirs(); 727 HiLiteMe.Cache.initializeOrClear(hiLiteServerCacheDirectoryName, null); 728 } 729 730 HiLiteMe.Cache cache = new HiLiteMe.Cache(hiLiteServerCacheDirectoryName); 731 732 useHiLiteServerCache(cache); 733 734 return this; 735 } 736 737 /** 738 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_HILITER> 739 * @param hiLiter Any valid implementation of the {@link HiLiter} interface 740 */ 741 public Upgrade setHiLiter(HiLiter hiLiter) 742 { 743 this.settingsBuilder.hiLiter = hiLiter; 744 return this; 745 } 746 747 748 // ******************************************************************************************** 749 // ******************************************************************************************** 750 // The Big Kahuna Burger. That is a tasty burger. Brad - did I break your concentration? 751 // ******************************************************************************************** 752 // ******************************************************************************************** 753 754 755 /** 756 * <EMBED CLASS='external-html' DATA-FILE-ID=U_GET_DEF_CSS_FILES> 757 * @return All Java-Doc Upgrader {@code '.css'} Files 758 * @see #setCustomCSSFiles(CSSFiles) 759 */ 760 public static CSSFiles retrieveDefaultCSSFilesFromJAR() 761 { 762 return LFEC.readObjectFromFile_JAR 763 (Upgrade.class, "data-files/AllCSSFiles.objdat", true, CSSFiles.class); 764 } 765 766 /** 767 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_CSS_FILES> 768 * @param cssFiles All Java-Doc Upgrader {@code '.css'} Files 769 * @see #retrieveDefaultCSSFilesFromJAR() 770 */ 771 public Upgrade setCustomCSSFiles(CSSFiles cssFiles) 772 { 773 this.settingsBuilder.cssFiles = cssFiles; 774 return this; 775 } 776 777 /** 778 * <EMBED CLASS='external-html' DATA-FILE-ID=U_GET_DEF_JS_FILE> 779 * @return The <B STYLE='color:red'><I>entire contents</I></B> of the {@code '.js'} File (read 780 * from disk), returned as a {@code String}. 781 */ 782 public static String retrieveDefaultJSFileFromJAR() 783 { 784 return LFEC.readObjectFromFile_JAR 785 (Upgrade.class, "data-files/JDU-JS.sdat", true, String.class); 786 } 787 788 /** 789 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_FAVICON_IF> 790 * @param faviconFileFormat An instance of {@link IF} - the Image-Format of the Favicon-File. 791 */ 792 public Upgrade setFaviconFileFormat(IF faviconFileFormat) 793 { 794 this.settingsBuilder.faviconImageFileName = 795 FAVICON_FILE_NAME + '.' + faviconFileFormat.toString(); 796 797 return this; 798 } 799 800 /** 801 * <EMBED CLASS='external-html' DATA-FILE-ID=U_ADD_HEADER_TAGS> 802 * @param headerTags HTML-Tags to be inserted into a page's {@code <HEAD>...</HEAD>} Section 803 */ 804 public Upgrade addHeaderTags(Iterable<TagNode> headerTags) 805 { 806 Vector<HTMLNode> ht = this.settingsBuilder.headerTags; 807 for (TagNode tn : headerTags) { ht.add(tn); ht.add(NEWLINE); } 808 return this; 809 } 810 811 /** 812 * <EMBED CLASS='external-html' DATA-FILE-ID=U_ADD_HEADER_BLOCK> 813 * @param headerStuff HTML-Block to be inserted into a page's {@code <HEAD>...</HEAD>} Section 814 */ 815 public Upgrade addHeaderBlock(Vector<HTMLNode> headerStuff) 816 { this.settingsBuilder.headerTags.addAll(headerStuff); return this; } 817 818 /** <EMBED CLASS='external-html' DATA-FILE-ID=U_RUN_LINKS_CHECKER> */ 819 public Upgrade runLinksChecker() 820 { 821 this.settingsBuilder.linksChecker = new LinksChecker(); 822 return this; 823 } 824 825 /** 826 * Sets a tab-replacement policy for code-hilited HTML. 827 * 828 * @param spacesPerTab The number of spaces that should be used as a substitue for a 829 * tab-character ({@code '\t'}) when hiliting source-code. 830 * 831 * @param relativeOrAbsolute When this parameter receives {@code TRUE}, a tab-character is 832 * used to symbolize however many spaces are needed to place the cursor at the next 833 * <B STYLE='color: red;'>rounded-integral</B> number-of-spaces - modulo the value in 834 * {@code 'spacesPerTab'}. 835 * 836 * <BR /><BR />If a tab-charcter is found at index {@code 13} in a line-of-code, and the value 837 * passed to {@code 'spacesPerTab'} were {@code 4}, then the number of spaces inserted would be 838 * {@code 3}. This is because precisely {@code 3} spaces would skip to index {@code 16}, which 839 * happens to be the next-highest <B STYLE='color: red;'>rounded-multiple</B> of {@code 4}. 840 * 841 * <BR /><BR />When this parameter receives {@code FALSE}, a tab-character is always 842 * replaced by the exact number of space-characters specified by {@code spacesPerTab}. 843 * 844 * @throws IllegalArgumentException If a number less than {@code 1} or greater than {@code 20} 845 * is passed to parameter {@code 'spacesPerTab'} 846 * 847 * @see StrIndent#setCodeIndent_WithTabsPolicyRelative(String, int, int) 848 * @see StrIndent#setCodeIndent_WithTabsPolicyAbsolute(String, int, String) 849 */ 850 public Upgrade setTabsPolicy(int spacesPerTab, boolean relativeOrAbsolute) 851 { 852 if ((spacesPerTab < 1) || (spacesPerTab > 20)) throw new IllegalArgumentException( 853 "A tab-character ('\t') cannot represent less than one or more than twenty " + 854 "spaces. You have passed [" + spacesPerTab + "]" 855 ); 856 857 final String SPACES = StringParse.nChars(' ', spacesPerTab); 858 859 this.settingsBuilder.indentor = (relativeOrAbsolute) 860 ? (String s) -> StrIndent.setCodeIndent_WithTabsPolicyRelative(s, 1, spacesPerTab) 861 : (String s) -> StrIndent.setCodeIndent_WithTabsPolicyAbsolute(s, 1, SPACES); 862 863 return this; 864 } 865 866 /** 867 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_CHECK_BALANCE> 868 * @param checkBalance The value of this parameter can turn the balance checker on or off. 869 */ 870 public Upgrade setCheckBalance(boolean checkBalance) 871 { 872 this.settingsBuilder.checkBalance = checkBalance; 873 return this; 874 } 875 876 /** 877 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_EXTRA_TASKS> 878 * 879 * @param extraTasks This function-pointer may be used to, sort-of, do extra processing on a 880 * JavaDoc HTML Documentation File while the vectorized-html file is already loaded into 881 * memory - and parsed. 882 * 883 * <BR /><BR />The class {@link JavaDocHTMLFile} provides many accessor methods to retrieve 884 * the Summary Tables, and the HTML Details - <I>along with reflection-classes about the 885 * {@link Method}'s, {@link Field}'s, etc... that they describe</I> 886 */ 887 public Upgrade setExtraTasks(Consumer<JavaDocHTMLFile> extraTasks) 888 { 889 this.settingsBuilder.extraTasks = extraTasks; 890 return this; 891 } 892 893 /** 894 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_PKGSUMM_CLEAN> 895 * @param packageSummaryCleaner Java Lambda for modifying Vectorized-HTML. 896 */ 897 public Upgrade setPackageSummaryCleaner(Consumer<Vector<HTMLNode>> packageSummaryCleaner) 898 { 899 this.settingsBuilder.packageSummaryCleaner = packageSummaryCleaner; 900 return this; 901 } 902 903 /** <EMBED CLASS='external-html' DATA-FILE-ID=U_USE_DEFAULT_PSC> */ 904 public Upgrade useDefaultPackageSummaryCleaner() 905 { 906 this.settingsBuilder.packageSummaryCleaner = PackageSummaryHTML::defaultCleaner; 907 return this; 908 } 909 910 /** 911 * Often, for the purposes of "development speed" during the development phase of a project, 912 * it can be of tremendous benefit to skip, altogether, the Upgrade Process of some of the 913 * Packages in a Project. 914 * 915 * <BR /><BR /><B CLASS=JDDescLabel>Filter Behavior:</B> 916 * 917 * <BR />Packages which are explicity named by the input parameter list {@code 'packageList'} 918 * are <B STYLE='color: red;'><I>INCLUDED</I></B> not 919 * <B STYLE='color: red;'><I>EXCLUDED</I></B> by the Internal Upgrder Logic. 920 * 921 * <BR /><BR /><B CLASS=JDDescLabel>Default Setting:</B> 922 * 923 * <BR />By default, initiating an {@code upgrade} will cause this Package's internal 924 * Upgrade Logic to iterate <B STYLE='color: red;'><I>ALL</I></B> Packages found / present in 925 * the {@code 'javadoc/'} output directory. 926 * 927 * <BR /><BR /><B CLASS=JDDescLabel>Input-Parameter Type:</B> 928 * 929 * <BR />If Java-HTML Package "{@link Torello.Java.Build Build}" is not actually being utilized 930 * by your Project's Build-System, there is a nearly identical variant of this method that 931 * accept's Package-Names as Java {@code String's}, instead of instances of class 932 * "{@link BuildPackage}". 933 * 934 * <BR /><BR />(Class {@link BuildPackage} is one of the Primary Data-Classes for the Build 935 * Tool {@link Torello.Java.Build}). 936 * 937 * @param packageList A list of instances of the {@link Torello.Java.Build Build} Package's 938 * class {@link BuildPackage}. 939 * 940 * @return {@code 'this'} instance, for method-invocation chaining. 941 * @see #setPackageList(String[]) 942 */ 943 public Upgrade setPackageList(Iterable<BuildPackage> packageList) 944 { 945 TreeSet<String> ts = new TreeSet<>(); 946 for (BuildPackage bp : packageList) ts.add(bp.fullName); 947 this.predicatesBuilder.packagesToUpgradeFilter = StrFilter.strListKEEP(ts, false)::test; 948 return this; 949 } 950 951 /** 952 * Often, for the purposes of "development speed" during the development phase of a project, 953 * it can be of tremendous benefit to skip, altogether, the Upgrade Process of some of the 954 * Packages in a Project. 955 * 956 * <BR /><BR /><B CLASS=JDDescLabel>Filter Behavior:</B> 957 * 958 * <BR />Packages which are explicity named by the input parameter list {@code 'packageList'} 959 * are <B STYLE='color: red;'><I>INCLUDED</I></B> not 960 * <B STYLE='color: red;'><I>EXCLUDED</I></B> by the Internal Upgrder Logic. 961 * 962 * <BR /><BR /><B CLASS=JDDescLabel>Default Setting:</B> 963 * 964 * <BR />By default, initiating an {@code upgrade} will cause this Package's internal 965 * Upgrade Logic to iterate <B STYLE='color: red;'><I>ALL</I></B> Packages found / present in 966 * the {@code 'javadoc/'} output directory. 967 * 968 * @param packageList A list of Package-Name's as a {@code String}. 969 * @return {@code 'this'} instance, for method-invocation chaining. 970 * @see #setPackageList(Iterable) 971 */ 972 public Upgrade setPackageList(String... packageList) 973 { 974 this.predicatesBuilder.packagesToUpgradeFilter = 975 StrFilter.strListKEEP(false, packageList)::test; 976 977 return this; 978 } 979 980 /** 981 * A Configuration-Setting for requesting that the Upgrader Auto-Generate the original Java 982 * {@code 'package-frame.html'} & {@code 'overview-frame.html'} Files. 983 * 984 * <EMBED CLASS='external-html' DATA-FILE-ID=U_SET_GEN_FRAMES> 985 * 986 * @param generateFrames The {@code boolean}-Setting for this Configuration-Field 987 * @return {@code 'this'} instance, for method-invocation chaining. 988 * 989 * @throws UpgradeException If {@code 'generateFrames'} is passed {@code FALSE}, but you have 990 * earlier configured / applied an {@code 'overview-frame.html'} sorter. 991 * 992 * @see PackageSummaryHTML#JD_FRAMES_WARNING_MESSAGE 993 */ 994 public Upgrade setGenerateFrames(boolean generateFrames) 995 { 996 this.settingsBuilder.generateFrames = generateFrames; 997 998 if ((! generateFrames) && (this.settingsBuilder.overviewFrameSections != null)) 999 1000 throw new UpgradeException( 1001 "Generate-Frames cannot be turned off if an Overview-Frame Sorter has already " + 1002 "been applied" 1003 ); 1004 1005 return this; 1006 } 1007 1008 /** 1009 * Generate and sort an {@code 'overview-frame.html'} File. 1010 * @param sectionNames List of "Categories" or "Sections" for the packages 1011 * @param sectionContents List of Packages for each Category / Section. 1012 * @return {@code 'this'} instance, for method-invocation chaining. 1013 */ 1014 public Upgrade setOverviewFrameSorter(String[] sectionNames, String[][] sectionContents) 1015 { 1016 // This can only be sorted if it is first created / turned-on. 1017 this.settingsBuilder.generateFrames = true; 1018 1019 this.settingsBuilder.overviewFrameSections = new ReadOnlyArrayList<String>(sectionNames); 1020 1021 // Generics & Arrays do not always look so nice... In the code below: 1022 // 1023 // String[][] sectionContents is cast to Object[], to "help" the javac Generics-Processor 1024 // Object o is then cast back to String[], also to "help" the javac Generics-Processor 1025 // 1026 // Note that this.settingsBuilder.overviewFramePackages is declared using type: 1027 // public ReadOnlyList<ReadOnlyList<String>> overviewFramePackages 1028 1029 this.settingsBuilder.overviewFramePackages = new ReadOnlyArrayList<ReadOnlyList<String>>( 1030 (Object o) -> new ReadOnlyArrayList<String>((String []) o), 1031 (Object[]) sectionContents 1032 ); 1033 1034 return this; 1035 } 1036 1037 // This is only used to prevent the "Overview Frame Sorter" from causing a Messager 1038 // Exception-Throw when the Build has Opted for a "Quick-Build" - and the Overview 1039 // Frame Sorter hasn't removed the Quick-Build Packages from its sort! 1040 // 1041 // Later this will also be used for the (upcoming - soon) "UNDER_DEVELOPMENT" BuildPackage 1042 // flag. 1043 // 1044 // This is an Internal-Method that is largely completely useless for the end user. Hence it is 1045 // Package-Visible (available through the "EXPORT_PORTAL") 1046 1047 void registerEliminatedBuildPackages(ReadOnlyList<BuildPackage> eliminatedBuildPackages) 1048 { this.settingsBuilder.eliminatedBuildPackages = eliminatedBuildPackages; } 1049}