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