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