1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | package Torello.JavaDoc.Messager; import java.io.File; import Torello.Java.StringParse; import Torello.Java.UnreachableError; import Torello.Java.C; import Torello.Java.StorageWriter; import Torello.JavaDoc.Declaration; public class PrintRecord { // ******************************************************************************************** // ******************************************************************************************** // Constructor & Immutable-Fields ==> Fields set in stone at time of construction // ******************************************************************************************** // ******************************************************************************************** // This Appendable allows the user to pick a place to store the log-contents to disk, or just // about any output-Appendable. This java.lang.Appendable may be specified/configured with the // class Upgrade - using the method: setLogFile // // NOTE: There are two methods for setting this field. One allows the user to provide a file // name, and the other allows them to provide any free-formed java.lang.Appendable. // // FINAL-IMMUTABLE & **PRIVATE** Instance-Field - Only Used inside this class private final Appendable logAppendable; // Here is the level of the Verbosity. The actual printing is done inside class MsgPkgPrivate, // and in that method, messages are only printed if they are above or equal to the current // Verbosity-Level final int verbosityLevel; // This just tells whether the above field is null. // TRUE => NON-NULL // FALSE => NULL // NOTE: This one is null final boolean hasLogAppendable; // Some stupid little thing, which I totally don't completely remember right now. // It is used inside the PrintHeading class. // Certain Verbosity-Levels necessitate a newline character final String VERBOSITY_LEVEL_NEW_LINE; // The "StorageWriter" Prints to the Screen. The String's that it saves inside of it's // "Storage", are then send to the 'logAppendable' - if-and-only-if the logAppendable is non // null! final StorageWriter screenWriterSW = new StorageWriter(); // This is used OVER-AND-OVER through out the Print-Messager & Print-Heading classes // It is "reset" whenever it is finished, rather than destroyed / freed. // // This is currently important because it allows the logic to avoid creating and destroying a // million little StringBuilder's. The only other point to "know about" is that StringBuilder // wasn't used at all a few months back (except "implicity", since the JDK, internally, uses a // StringBuilder when doing its concatenation routines). // // Now that some of the Parse Code is being turned into an external thing, there is the // potential to re-use the messager code. If that happens, a StringBuilder is used to retrieve // the Error-Message Strings, and then shove them into an exception instead! (Thereby // revering the original premise for having a "Messager" at all, namely avoid exception throws) final StringBuilder sb = new StringBuilder(); // The actual constructor PrintRecord(final int verbosityLevel, final Appendable logAppendable) { this.verbosityLevel = verbosityLevel; this.VERBOSITY_LEVEL_NEW_LINE = (verbosityLevel < 2) ? "\n" : ""; this.logAppendable = logAppendable; this.hasLogAppendable = (logAppendable != null); } // ******************************************************************************************** // ******************************************************************************************** // Static-Constants // ******************************************************************************************** // ******************************************************************************************** private static final byte mode_FILE_AND_PROC_ONLY = 1; private static final byte mode_FILE_PROC_AND_DECL = 2; private static final int indentation_FILE_AND_PROC_ONLY = 8; private static final int indentation_FILE_PROC_AND_DECL = 12; // These are **ONLY** used in the getter below private static final String I8 = StringParse.nChars(' ', 8); private static final String I12 = StringParse.nChars(' ', 12); // There is a very detail explanation for why "19" and "23" have been chosen, below! // // final String fodIndent = " Processing ".length() + fileOrDir.length() + 2; // // ==> " Directory " is 11 (9 + 2), " File " is 6 (4 + 2) // ==> " Processing " is 12 spaces long // ==> 12 + (11 or 6) // ==> 23 or 18 private static final String I18 = StringParse.nChars(' ', 18); private static final String I23 = StringParse.nChars(' ', 23); // ******************************************************************************************** // ******************************************************************************************** // PRIVATE & **MUTABLE** Instance-Fields // ******************************************************************************************** // ******************************************************************************************** private int errorCount = 0; private int warningCount = 0; // The mode it's using private byte mode = mode_FILE_AND_PROC_ONLY; // This sets the indentation level - as a number of space ' ' characters private Integer indentation = indentation_FILE_AND_PROC_ONLY; // The "current" Java Doc HTML File being analyzed. Whenever an error occurs, presuming this // field is non-null, it will be printed at the top of the error message. private String fileName = null; // In this class, there is a method which "sets" the file-name. This is done many times insde // the JDU-Internal classes. Whenever the file-name is set, there is a second parameter // included in the "set" method that mandates / requires a brief-small description of what the // file is also be provided. private String fileNameKind = null; // This shall be set to ==> ? " Directory " : " File "; private String fileOrDir = null; // There is a very detail explanation for why "19" and "23" have been chosen, ABOVE! // final String fodIndent = " Processing ".length() + fileOrDir.length() + 2; private String fodIndentation = null; // The first time that an error or warning is printed, the file-name being "analyzed" must be // printed at the top of the message. All subsequent messges do not need this error // header message, AS LONG AS THE SAME FILE IS STILL BEING ANALYZED. // // When the Program Control-Flow sends a message that a new File-Name is being analzyed, then // the boolean is reset to FALSE immediately! // // Whenever this boolean is FALSE, the File-Name being anaylzed has to be printed to any output // error-message or warning-messages that are printed to the user's terminal. private boolean printedFileNameAlready = false; // The "current" declaration about which error messages will be printed (if there are any) private Declaration declaration = null; // The "EmbedTag" processor treats the "TopDescription" as one of the details section. It // really isn't "a hack" - because the code is so long and the "Top Description" Embed Tag's // are the exact same as the "Details" EmbedTag's. This is also true for the "HiLiteDividers" // // This, sort of, "overrides" the "detailSection" boolean. Since the "Top Description" part of // any Java-Doc Web-Page also needs to be analyzed-and-updated, it is altogether possible that // that an error-or-warning message for the Top-Description HTML might be generated. // // This needs to be handled IN THE EXACT SAME MANNER as error-or-warning messages are handled // for the Detail-Sections. It needes to be printed to the user's terminal before the actual // error-message itself! // // This boolean just says: JDU isn't currently processing **ANY** Detail-Sections, so don't // print the Detail-Section's name, instead please print a friendly message saying // that the "Top-Description Segment" of the Java-Doc Web-Page is being processed and analyzed // at the moment. private boolean topDescriptionAsDecl = false; // The first time that an error or warning is printed, the detail-section location must be // printed at the top of the message. All subsequent messges do not need this error // header message. private boolean printedDeclAlready = false; // The purpose of is to - sort of - "Prevent" reprinting the Processor-Name and / or the // Sub-Processor Name (over and over) when the Messager Receives requests to print errors over // and over that are from the exact same Messager-Processor Location. // // It looks **REALLY UGLY** to see the exact same, long-winded, Processor Location over and // over for the exact same type of error. private Where_Am_I prev_WHERE_AM_I = null; // ******************************************************************************************** // ******************************************************************************************** // PACKAGE-PRIVATE **GETTERS** - Used in "PrintHeading" // ******************************************************************************************** // ******************************************************************************************** boolean hadErrors() { return this.errorCount > 0; } boolean hadWarnings() { return this.warningCount > 0; } int getErrorCount() { return this.errorCount; } int getWarningCount() { return this.warningCount; } int getIndentation() { return this.indentation; } byte getMode() { return this.mode; } String getFileName() { return this.fileName; } String getFileNameKind() { return this.fileNameKind; } boolean alreadyPrintedFileName() { return this.printedFileNameAlready; } Declaration getDeclaration() { return this.declaration; } boolean topDescriptionAsDecl() { return this.topDescriptionAsDecl; } boolean alreadyPrintedDecl() { return this.printedDeclAlready; } boolean modeFileAndProc() { return this.mode == mode_FILE_AND_PROC_ONLY; } boolean modeFileProcAndDecl() { return this.mode == mode_FILE_PROC_AND_DECL; } String isFileOrDir() { return this.fileOrDir; } String fodIndentation() { return this.fodIndentation; } boolean whereAmIChanged(final Where_Am_I WHERE_AM_I) { return this.prev_WHERE_AM_I == WHERE_AM_I; } String getIndentationStr() { if (this.indentation == 8) return I8; if (this.indentation == 12) return I12; throw new UnreachableError(); } // ******************************************************************************************** // ******************************************************************************************** // Some simple setters // ******************************************************************************************** // ******************************************************************************************** void printingFileNameRightNow() { this.printedFileNameAlready = true; } void printingFirstDeclRightNow() { this.printedDeclAlready = true; } int incErrorCountAndCheck() { if (++this.errorCount > 25) throw new ReachedMaxErrors(); else return this.errorCount; } int incWarningCount() { return ++this.warningCount; } void setPreviouseWhereAmI(final Where_Am_I WHERE_AM_I) { this.prev_WHERE_AM_I = WHERE_AM_I; } // ******************************************************************************************** // ******************************************************************************************** // Messager Control Setters // ******************************************************************************************** // ******************************************************************************************** void setCurrentFileName(final String fName, final String fNameKind) { final boolean b = fName.endsWith(File.separator); this.fileNameKind = fNameKind; this.fileName = fName; this.fileOrDir = b ? " Directory " : " File "; this.fodIndentation = b ? I18 : I23; this.printedFileNameAlready = false; this.indentation = indentation_FILE_AND_PROC_ONLY; this.mode = mode_FILE_AND_PROC_ONLY; // Also clear the detail section, and the entity this.declaration = null; this.printedDeclAlready = false; } void setTopDescriptionSection() { this.declaration = null; this.printedDeclAlready = false; this.topDescriptionAsDecl = true; this.indentation = indentation_FILE_PROC_AND_DECL; this.mode = mode_FILE_PROC_AND_DECL; } void setDeclaration(final Declaration declaration) { this.declaration = declaration; this.printedDeclAlready = false; this.topDescriptionAsDecl = false; this.indentation = indentation_FILE_PROC_AND_DECL; this.mode = mode_FILE_PROC_AND_DECL; } // ******************************************************************************************** // ******************************************************************************************** // Do Something // ******************************************************************************************** // ******************************************************************************************** void writeSBToScreen() { this.screenWriterSW.print(this.sb.toString()); this.sb.setLength(0); } void checkPointLog() { final String textAlreadyWrittenToScreen = C .toHTML(this.screenWriterSW.getString(), true, true, true) .replace("\t", " "); this.screenWriterSW.erase(); try { this.logAppendable.append(textAlreadyWrittenToScreen); } catch (Exception e) { this.setCurrentFileName("User Provided Log", null); Messager.assertFail( e, "Exception thrown while attempting to write to User-Provided Appendable-Log\n" + "The Appendable which was provided to the class 'Torello.JavaDoc.Upgrade' has " + "thrown an Exception while attempting to write to it.", JDUMessager.PrintRecord ); } } } |