001package Torello.HTML; 002 003import Torello.JavaDoc.JDHeaderBackgroundImg; 004 005/** 006 * This class is mostly a wrapper for class <CODE>java.lang.String</CODE>, and serves as 007 * the abstract parent of the three types of HTML elements offered by the Java HTML Library. 008 * 009 * <EMBED CLASS='external-html' DATA-FILE-ID=HTML_NODE> 010 * 011 * @see TagNode 012 * @see TextNode 013 * @see CommentNode 014 */ 015@JDHeaderBackgroundImg(EmbedTagFileID={"HTML_NODE_HEADER", "HTML_NODE_SUB_IMG"}) 016public abstract class HTMLNode implements CharSequence, java.io.Serializable, Cloneable 017{ 018 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 019 public static final long serialVersionUID = 1; 020 021 /** 022 * This is an immutable field. It stores the complete contents of an HTML node. It can be 023 * either the <B>"textual contents"</B> 024 * of an HTML {@code TagNode}, or the text (directly) of the text-inside of an HTML page! 025 * 026 * <BR /><BR /> 027 * <B>FOR INSTANCE:</B> 028 * 029 * <BR /><BR /><UL CLASS=JDUL> 030 * 031 * <LI>A subclass of HTMLNode - <CODE>TagNode</CODE> - could contain the String 032 * <SPAN STYLE="color: red;"><SPAN STYLE="CSS INFO">"</SPAN> 033 * <I>inside this <CODE><B>str field</CODE></B> here.</I> 034 * </LI> 035 * 036 * <LI> The other sub-class of HTML - <CODE>TextNode</CODE> - could contain the {@code String} 037 * <SPAN STYLE="color: red;">"This is a news-page from www.Gov.CN Chinese Government 038 * Portal."</SPAN> <I>inside this <CODE><B>str field</CODE></B> here.</I> 039 * </LI> 040 * 041 * </UL> 042 * 043 * <BR /><B>NOTE:</B> Because sub-classes of {@code HTMLNode} are all immutable, generally, 044 * if you wish to change the contents of an HTML page, a programmer is required to create new 045 * nodes, rather than changing these fields. 046 */ 047 public final String str; 048 049 /** 050 * Constructor that builds a new {@code HTMLNode} 051 * 052 * @param s A valid string of an HTML element. 053 */ 054 protected HTMLNode(String s) 055 { this.str = s; } 056 057 /** 058 * Java's hash-code requirement. 059 * 060 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 061 * 062 * <BR />This method is final, and cannot be modified by sub-classes. 063 * 064 * @return A hash-code that may be used when storing this node in a java sorted-collection. 065 */ 066 public final int hashCode() 067 { return this.str.hashCode(); } 068 069 /** 070 * Java's {@code public boolean equals(Object o)} requirements. 071 * 072 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 073 * 074 * <BR />This method is final, and cannot be modified by sub-classes. 075 * 076 * @param o This may be any Java Object, but only ones of {@code 'this'} type whose 077 * internal-values are identical will cause this method to return {@code TRUE}. 078 * 079 * @return {@code TRUE} If {@code 'this'} equals another object {@code HTMLNode.} 080 */ 081 public final boolean equals(Object o) 082 { 083 if (o == null) return false; 084 if (o == this) return true; 085 086 if (! this.getClass().equals(o.getClass())) return false; 087 088 return ((HTMLNode) o).str.equals(this.str); 089 } 090 091 /** 092 * Sub-classes of {@code HTMLNode} must be {@code Cloneable.} 093 * 094 * @return Must return an identical copy of {@code 'this'} node. The object reference cannot 095 * be {@code 'this'} reference. 096 */ 097 public abstract HTMLNode clone(); 098 099 100 // ********************************************************************************************** 101 // CharSequence Methods 102 // ********************************************************************************************** 103 104 /** 105 * Java's {@code toString()} requirement. 106 * 107 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 108 * 109 * <BR />This method is final, and cannot be modified by sub-classes. 110 * 111 * @return A {@code String}-representation of this {@code HTMLNode.} 112 */ 113 public final String toString() { return this.str; } 114 115 /** 116 * Returns the char value at the specified index of the field: {@code public final String str}. 117 * An index ranges from {@code '0'} (zero) to {@code HTMLNode.str.length() - 1.} The first 118 * {@code char} value of the sequence is at index zero, the next at index one, and so on, as 119 * for array indexing. 120 * 121 * <BR /><BR /><B>NOTE:</B> If the {@code char} value specified by the index is a surrogate, 122 * the surrogate value is returned. 123 * 124 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 125 * 126 * <BR />This method is final, and cannot be modified by sub-classes. 127 * 128 * @param index The index of the {@code char} value to be returned 129 * 130 * @return The specified {@code char} value 131 */ 132 public final char charAt(int index) { return str.charAt(index); } 133 134 /** 135 * Returns the length of the field {@code public final String str}. 136 * The length is the number of 16-bit chars in the sequence. 137 * 138 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 139 * 140 * <BR />This method is final, and cannot be modified by sub-classes. 141 * 142 * @return the number of {@code chars} in {@code this.str} 143 */ 144 public final int length() { return str.length(); } 145 146 /** 147 * Returns a {@code CharSequence} that is a subsequence of the {@code public final String str} 148 * field of {@code 'this' HTMLNode}. 149 * The subsequence starts with the {@code char} value at the specified index and ends with the 150 * {@code char} value at index {@code end - 1.} The length (in chars) of the returned sequence 151 * is {@code end - start}, so if {@code start == end} then an empty sequence is returned. 152 * 153 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 154 * 155 * <BR />This method is final, and cannot be modified by sub-classes. 156 * 157 * @param start The start index, inclusive 158 * @param end The end index, exclusive 159 * 160 * @return The specified subsequence 161 */ 162 public final CharSequence subSequence(int start, int end) 163 { return str.substring(start, end); } 164 165 166 // ******************************************************************************************** 167 // ******************************************************************************************** 168 // 'is' Optimization Methods 169 // ******************************************************************************************** 170 // ******************************************************************************************** 171 172 173 /** 174 * This method will return {@code TRUE} for any instance of {@code 'CommentNode'}. 175 * 176 * <BR /><BR />The purpose of this method is to efficiently return {@code TRUE} whenever 177 * an instance of {@code 'HTMLNode'} should be checked to see if it is actually an inherited 178 * instance of {@code CommentNode}. This is (marginally) more efficient than using the Java 179 * {@code 'instanceof'} operator. 180 * 181 * @return This (top-level inheritance-tree) method always returns {@code FALSE}. The 182 * {@code '.java'} file for {@code class CommentNode} overrides this method, and returns 183 * {@code TRUE}. 184 * 185 * @see CommentNode#isCommentNode() 186 */ 187 public boolean isCommentNode() 188 { 189 // This method will *only* be over-ridden by subclass CommentNode, where it shall return 190 // TRUE. Neither class TextNode, nor class TagNode will over-ride this method. 191 192 return false; 193 } 194 195 /** 196 * This method will return {@code TRUE} for any instance of {@code 'TextNode'}. 197 * 198 * <BR /><BR />The purpose of this method is to efficiently return {@code TRUE} whenever 199 * an instance of {@code 'HTMLNode'} should be checked to see if it is actually an inherited 200 * instance of {@code TextNode}. This is (marginally) more efficient than using the Java 201 * {@code 'instanceof'} operator. 202 * 203 * @return This (top-level inheritance-tree) method always returns {@code FALSE}. The 204 * {@code '.java'} file for {@code class TextNode} overrides this method, and returns 205 * {@code TRUE}. 206 * 207 * @see TextNode#isTextNode() 208 */ 209 public boolean isTextNode() 210 { 211 // This method will *only* be over-ridden by subclass CommentNode, where it shall return 212 // TRUE. Neither class TextNode, nor class TagNode will over-ride this method. 213 214 return false; 215 } 216 217 /** 218 * This method will return {@code TRUE} for any instance of {@code 'TagNode'}. 219 * 220 * <BR /><BR />The purpose of this method is to efficiently return {@code TRUE} whenever 221 * an instance of {@code 'HTMLNode'} should be checked to see if it is actually an inherited 222 * instance of {@code TagNode}. This is (marginally) more efficient than using the Java 223 * {@code 'instanceof'} operator. 224 * 225 * @return This (top-level inheritance-tree) method always returns {@code FALSE}. The 226 * {@code '.java'} file for {@code class TagNode} overrides this method, and returns 227 * {@code TRUE}. 228 * 229 * @see TagNode#isTagNode() 230 */ 231 public boolean isTagNode() 232 { 233 // This method will *only* be over-ridden by subclass TagNode, where it shall return 234 // TRUE. Neither class TextNode, nor class CommentNode will over-ride this method. 235 236 return false; 237 } 238 239 240 // ******************************************************************************************** 241 // ******************************************************************************************** 242 // TagNode Optimization Methods 243 // ******************************************************************************************** 244 // ******************************************************************************************** 245 246 247 /** 248 * <EMBED CLASS='external-html' DATA-RET=null DATA-FILE-ID=OPEN_TAG_PWA_DESC> 249 * 250 * <BR /><BR />This makes the process of finding {@code TagNode's} having a particular 251 * attribute much more efficient. 252 * 253 * <BR /><BR />The purpose of this method is to quickly return a node that has been cast to 254 * an instance of {@code TagNode}, if it is, indeed, a {@code TagNode} <B><I>and if</I></B> it 255 * has an internal-{@code String} long-enough to possibly contain attributes (inner-tags). 256 * 257 * @return This method shall always return null, unless this method has been overridden by a 258 * sub-class. Only {@code TagNode} overrides this method, and this method will return 259 * {@code 'this'} instance, if and only if the following conditions hold: 260 * 261 * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_PWA_RET> 262 * 263 * @see TagNode#openTagPWA() 264 * @see isOpenTagPWA() 265 */ 266 public TagNode openTagPWA() 267 { 268 // This method will *only* be over-ridden by subclass TagNode. 269 // For instances of inheriting class TextNode and CommentNode, this always returns null. 270 // In 'TagNode' this method returns true based on the 'isClosing' field from that class, 271 // and the length of the 'str' field from this class. 272 273 return null; 274 } 275 276 /** 277 * <EMBED CLASS='external-html' DATA-RET=null DATA-FILE-ID=OPEN_TAG_DESC> 278 * 279 * @return This method shall always return null, unless this method has been overridden by a 280 * sub-class. Only {@code TagNode} overrides this method, and this method will return 281 * {@code 'this'} instance, if and only if the following conditions hold: 282 * 283 * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_PWA_RET> 284 * 285 * <BR /><BR />When the overridden {@code TagNode} sub-class returns a non-null result, that 286 * value will <B>always be equal to {@code 'this'}</B> 287 * 288 * @see TagNode#openTag() 289 */ 290 public TagNode openTag() 291 { 292 // This method will *only* be over-ridden by subclass TagNode. 293 // For instances of inheriting class TextNode and CommentNode, this always returns null. 294 // In 'TagNode' this method returns true based on that class 'isClosing' field. 295 296 return null; 297 } 298 299 300 // ******************************************************************************************** 301 // ******************************************************************************************** 302 // TagNode Optimization Methods, Part II - Same as above, but returns boolean 303 // ******************************************************************************************** 304 // ******************************************************************************************** 305 306 307 /** 308 * <EMBED CLASS='external-html' DATA-RET=false DATA-FILE-ID=OPEN_TAG_PWA_DESC> 309 * <EMBED CLASS='external-html' DATA-RET=false DATA-FILE-ID=IS_OPEN_TAG_PWA_EX> 310 * 311 * @return This method shall always return {@code FALSE}, unless it has been overriden by a 312 * subclass. Subclass {@link TagNode} overrides this, and will return {@code TRUE} if and only 313 * if the following conditions hold: 314 * 315 * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_PWA_RET> 316 * 317 * @see TagNode#isOpenTagPWA() 318 * @see #openTagPWA() 319 */ 320 public boolean isOpenTagPWA() 321 { 322 // This method will *only* be over-ridden by subclass TagNode. 323 // For instances of inheriting class TextNode and CommentNode, this always returns false. 324 // In 'TagNode' this method returns TRUE based on the 'isClosing' field from that class, 325 // and the length of the 'str' field from this class. 326 327 return false; 328 } 329 330 /** 331 * <EMBED CLASS='external-html' DATA-RET=false DATA-FILE-ID=OPEN_TAG_DESC> 332 * 333 * <BR /><BR />This method will function almost identically to {@link #openTag()}, with the 334 * subtle difference being that it returns a {@code TRUE / FALSE} boolean, instead of an 335 * instance-reference. 336 * 337 * @return This method shall always return {@code FALSE}, unless it has been overriden by a 338 * subclass. Subclass {@link TagNode} overrides this, and will return {@code TRUE} if and only 339 * if the following conditions hold: 340 * 341 * <EMBED CLASS='external-html' DATA-FILE-ID=OPEN_TAG_RET> 342 * 343 * @see TagNode#isOpenTag() 344 * @see #openTag() 345 */ 346 public boolean isOpenTag() 347 { 348 // This method will *only* be over-ridden by subclass TagNode. 349 // For instances of inheriting class TextNode and CommentNode, this always returns FALSE. 350 // In 'TagNode' this method returns TRUE based on that class 'isClosing' field. 351 352 return false; 353 } 354 355 356 // ******************************************************************************************** 357 // ******************************************************************************************** 358 // 'if' loop-optimizers 359 // ******************************************************************************************** 360 // ******************************************************************************************** 361 362 363 /** 364 * <B STYLE='color: red;'>Loop Optimization Method</B> 365 * 366 * <BR /><BR />When this method is invoked on an instance of sub-class {@link TagNode}, 367 * this method produces {@code 'this'} instance. 368 * 369 * @return This method is overriden by sub-class {@code TagNode}, and in that class, this 370 * method simply returns {@code 'this'}. The other sub-classes of this ({@code abstract}) 371 * class inherit this version of this method, and therefore return null. 372 * 373 * @see TagNode#ifTagNode() 374 */ 375 public TagNode ifTagNode() 376 { 377 // This method will *only* be over-ridden by subclass TagNode, where it shall return 378 // 'this'. Neither class TextNode, nor class CommentNode will over-ride this method. 379 380 return null; 381 } 382 383 /** 384 * <B STYLE='color: red;'>Loop Optimization Method</B> 385 * 386 * <BR /><BR />When this method is invoked on an instance of sub-class {@link TextNode}, 387 * this method produces {@code 'this'} instance. 388 * 389 * @return This method is overriden by sub-class {@code TextNode}, and in that class, this 390 * method simply returns {@code 'this'}. The other sub-classes of this ({@code abstract}) 391 * class inherit this version of this method, and therefore return null. 392 * 393 * @see TextNode#ifTextNode() 394 */ 395 public TextNode ifTextNode() 396 { 397 // This method will *only* be over-ridden by subclass TextNode, where it shall return 398 // 'this'. Neither class TagNode, nor class CommentNode will over-ride this method. 399 400 return null; 401 } 402 403 /** 404 * <B STYLE='color: red;'>Loop Optimization Method</B> 405 * 406 * <BR /><BR />When this method is invoked on an instance of sub-class {@link CommentNode}, 407 * this method produces {@code 'this'} instance. 408 * 409 * @return This method is overriden by sub-class {@code CommentNode}, and in that class, this 410 * method simply returns {@code 'this'}. The other sub-classes of this ({@code abstract}) 411 * class inherit this version of this method, and therefore return null. 412 * 413 * @see CommentNode#ifCommentNode() 414 */ 415 public CommentNode ifCommentNode() 416 { 417 // This method will *only* be over-ridden by subclass CommentNode, where it shall return 418 // 'this'. Neither class TagNode, nor class TextNode will over-ride this method. 419 420 return null; 421 } 422 423 424 // ******************************************************************************************** 425 // ******************************************************************************************** 426 // 'is' loop-optimizers 427 // ******************************************************************************************** 428 // ******************************************************************************************** 429 430 431 /** 432 * Compile-Time "Syntactic Sugar" for casting an {@code HTMLNode} to a {@code TagNode}. 433 * 434 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 435 * 436 * <BR />This method is final, and cannot be modified by sub-classes. 437 * 438 * @return Simply returns {@code 'this'} instance. (Note that the method 439 * {@code Class.cast(Object)} <I>doesn't actually do *anything*</I>, other than provide the 440 * compile-time logic some 'proof' in its type-analysis) 441 * 442 * @throws ClassCastException 443 * <BR /><B CLASS=JDDescLabel>Important:</B> 444 * <BR />If the instance is a {@link TextNode} or {@code CommentNode}, rather than a 445 * {@link TagNode}, then (naturally) the JVM will immediately throw a casting exception. 446 */ 447 public final TagNode asTagNode() { return TagNode.class.cast(this); } 448 449 /** 450 * Compile-Time "Syntactic Sugar" for casting an {@code HTMLNode} to a {@code TextNode}. 451 * 452 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 453 * 454 * <BR />This method is final, and cannot be modified by sub-classes. 455 * 456 * @return Simply returns {@code 'this'} instance. (Note that the method 457 * {@code Class.cast(Object)} <I>doesn't actually do *anything*</I>, other than provide the 458 * compile-time logic some 'proof' in its type-analysis) 459 * 460 * @throws ClassCastException 461 * <BR /><B CLASS=JDDescLabel>Important:</B> 462 * <BR />If the instance is a {@link TagNode} or {@code CommentNode}, rather than a 463 * {@link TextNode}, then (naturally) the JVM will immediately throw a casting exception. 464 */ 465 public final TextNode asTextNode() { return TextNode.class.cast(this); } 466 467 /** 468 * Compile-Time "Syntactic Sugar" for casting an {@code HTMLNode} to a {@code CommentNode}. 469 * 470 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 471 * 472 * <BR />This method is final, and cannot be modified by sub-classes. 473 * 474 * @return Simply returns {@code 'this'} instance. (Note that the method 475 * {@code Class.cast(Object)} <I>doesn't actually do *anything*</I>, other than provide the 476 * compile-time logic some 'proof' in its type-analysis) 477 * 478 * @throws ClassCastException 479 * <BR /><B CLASS=JDDescLabel>Important:</B> 480 * <BR />If the instance is a {@link TagNode} or {@code TextNode}, rather than a 481 * {@link CommentNode}, then (naturally) the JVM will immediately throw a casting exception. 482 */ 483 public final CommentNode asCommentNode() { return CommentNode.class.cast(this); } 484}