Class Library: Stream Objects

Data. An abstract class which encapsulates a a data stream object, including path and source variables, and a data buffer for storing the stream's data elements; subclasses must define its read() and/or write() methods. Because Data is itself an extension of the Thread class, reading and writing of the data stream occurs in its own thread of execution and thus takes full advantage of Java's built-in multithreading features to make the processing of long streams significantly faster.

package earthstones
import java.applet.*;
java.util.*;
class declaration public abstract class Data extends Thread
static constants public static final int INPUT = 1;
public static final int OUTPUT = 2
variables protected Container webApp = null; Reference to the main (host) applet.
protected int type; Designates type (INPUT or OUTPUT) of this data object.
protected String path = null; Set to path of the data stream (e.g., http://myServer/).
protected String source = null; The data stream's source (e.g., http://myServer/Text.htm). Note: the user is responsible for insuring that the value set here is a valid URL.
protected Document document = null; The document object with which this data object is associated.
protected DataBuffer data = null; The object's data buffer. This is the destination for INPUT data objects.
protected DataBuffer input = null; The source for OUTPUT Data objects.
protected DocElement output = null; An axillary object which may be written to by a subclass' write() method.
protected Vector outputTarget; The object to which output will be added
when the write method has finished.
constructors Data(Container app, Document doc,
int typ))
Creates a Data object of type typ associated with application or applet app. Initializes the object's data buffer data to a new DataBuffer object and calls start() which in turn executes run() in its own thread of execution. This is the typical contructor syntax for a Txt or Html INPUT object.
Data(Container app, Document doc,
int typ, DataBuffer inpt)
This constructor form also sets the Data object's data buffer data to that specified by the inpt parameter and also sets its outputTarget variable to document.data by default. This is the typical contructor syntax for a Doc subclass object for which the inpt parameter is the data buffer of an HtmlTag object.
Data(Container app, Document doc,
int typ, DataBuffer inpt,
DocElement out, String src)
This constructor form also sets the Data object's output variable to that specified by the DocElement instance out and sets its source variable to src. This is the typical contructor syntax for an HtmlTag subclass object for which the inpt parameter is the data buffer of an Html or Txt object, out is a Paragraph object initialized to null, and src is set to inpt.source() to pass along information about the initial source of the data stream needed to resolve URL references encountered in the HTML source.
Data(Container app, Document doc,
int typ, DataBuffer inpt,
DocElement out, Vector tgt,
String src)
This constructor syntax is used by HtmlTag.setExtTag() in creating another instance of HtmlTag to process a Table object in its own thread. In this case the parameter tgt is set to null to override its default assignment to document.data and thus prevent the Data.write() method from writing it again to document.data.
methods run() If type is INPUT, calls read(); otherwise, calls write().
public void read() This method establishes an InputStream istr object associated with source and then calls read(istr). If resource cannot be read, an error message is generated for display in the document window.
abstract void read(InputStream iStr) throws IOException; This abstract method must be implemented in subclasses.
public void write() 1) Loops while (input.hasMoreElements()) and, if elem = input.nextElement() is not null, calls write(elem).
2) I outputTarget and output are both not null, calls outputTarget.addElement(output).
3) The calls write(null) to signal that all data have been written.
abstract void write(Object obj); This abstract method must be implemented in subclasses. Note that this method must check for (obj == null) and take appropriate action.
The next 3 methods may be useful in the event that an OUTPUT Data object needs to know about its initial source.
public void setSource(String val) Set's object's source variable.
public String source() It the Data object's type is INPUT, loops while(source == null) and then returns source; otherwise, returns "".
public String setPath(String url) Sets path to the portion of a String url representing a URL up to, but not including, the last instance of "/"; returns path.

DataBuffer. This class is used by Data objects to store a data stream. It adds enumeration-like methods hasMoreElements() and nextElement() as well as an isLoaded flag to signal that all data from some input source (i.e., a data stream or another data buffer) has been written to the data buffer.

package earthstones
import java.util.*;
This dynamic buffer object is written to by its source using the write() method implemented here and read from by calls to the hasMoreElements() and nextElement() methods issued by its client object.

The buffer has desirable Enumeration-like properties: its (now dynamic) elements can be iterated over using a loop of the form:

while (file.data.hasMoreElements()) {
if ((elem = data.nextElement()) != null) [process elem]
}
class declaration public class DataBuffer extends Vector
protected boolean isLoaded = false; Set to true when source object has finished loading its data source into the buffer. IMPORTANT: It is the responsiblity of the source object to set this variable.
constructors DataBuffer() Calls super().
methods public synchronized Object nextElement() If size() is 0, returns null. Otherwise removes and returns elementAt(0). Should always be proceeded by the call hasMoreElements().
public synchronized boolean hasMoreElements() If (!isLoaded || (isLoaded && (size() > 0))) returns true; otherwise, returns false.
protected synchronized void setIsLoaded(boolean val) Sets the variable isLoaded.
public synchronized boolean isLoaded() Returns isLoaded.
public synchronized void write(Object elem) The default write() method adds Object elem to this Object.

Txt. Defines the read() method for interpreting a plain text data stream along with a DataBuffer object to store the stream's data as a collection of (CRLF-delimited) lines.

package earthstones
import java.awt.*;
java.applet.*;
java.util.*;
java.io.*;
java.net.*;
class declaration public class Txt extends Data
private String header = ""; Concantenates any CGI header strings; is written data buffer prior to any data or HTML code.
private boolean hasData = false; Indicates that the end of the CGI header has been reached. Set when either:
1) a blank line is encountered indicating the end of the header, or
2) the first HTML bracket < is encountered.
constructors Txt(Container app, Document doc) Constructs a Txt object associated with program (Applet or Application) app and Document doc. Calls super(app, doc, INPUT).
methods public void read(InputStream iStr)
throws IOException
Creates a DataInput object s associated with InputStream iStr and loops while(!data.isLoaded), repeatedly calling readFromStream(s).
private void readFromStream(DataInput s)
throws IOException
1) Loops while ((line = s.readLine()) != null).
1a) If hasData is not set, checks to see that line is still part of the header.
1a1) If so, appeads (line + " ") to header variable.
1a2) Otherwise, calls data.write(header) and, if line is not blank, data.write(line); then sets hasData.
1b) Otherwise, calls data.write(line).
2) Calls data.setIsLoaded(true).
public void write(Object obj) For this INPUT object, write() does nothing.

Html. Defines the read() method for interpreting an HTML data stream along with a DataBuffer object to store the stream's data as a collection of extended tags: an HTML tag delimited by <...> together with its tail--any subsequent text up to the next tag.

package earthstones
import java.awt.*;
java.applet.*;
java.util.*;
java.io.*;
java.net.*;
class declaration public class Html extends Data
variables private Paragraph resultsPar; The first two private variables are used in setting document.results for CGI results.
private boolean setCgiResults
= false;
private boolean foundBody = false; This variable is set when either the HTML document's <body> tag  or a javascript BodyTag function has been encountered. Output to the data buffer begins at this point and the input stream prior to this point is discarded.
constructors Html(Container app, Document doc) Constructs an Html object associated with program (Applet or Application) app and Document doc. Calls super(app, doc, INPUT).
methods public void read(InputStream iStr)
throws IOException
1) Creates a BufferedInputStream  s associated with InputStream iStr and loops while ((inpt = readFromStream(s)).length() > 0).
2) For each buffer inpt read, the private method nextTag() is called repeatedly to parse the input stream into extended tags consisting of an HTML tag and its subsequent text (up to the next tag in the stream).
3) Each extended tag is written to the Html objects data buffer through a call to the private helper method write(extTag, inpt, idx) where idx marks the location of extTag in inpt.
4) Any tag fragment at the end of inpt is prepended to the next buffer read from the input stream until all the data have been read.
5) The method data.setIsLoaded(true) is called and, if setCgiResults is set, document.results.setIsLoaded(true) is called.
private String readFromStream(BufferedInputStream s)
throws IOException
This private method reads 4096 bytes from the BufferedInputStream object s and returns them as a string. This method accounts for the fact that text editors typically strip trailing spaces from end of wrapping text lines by adding them back upon encountering a CRLF sequence.
private String nextTag(String dataStream, int startHere) This method returns the next extended tag in the string buffer dataStream.
public void write(Object obj) For this INPUT object, write() does nothing.
private int write(String extTag, String inptString, int index) This private helper method writes extended tag extTag to the Html object's data buffer where index marks the location of extTag in input buffer inptString. Manages a number of special cases including the HTML <body> tag (or javascript BodyTag function), the HTML+ <error> tag, and the output of CGI results.

HtmlTag. Reads the data buffer of a Txt or Html object, interprets its HTML tags, and writes the results to a Document object's data buffer as a collection of Paragraph objects. In the case of a Txt stream, each line is interpreted as a Paragraph consisting of a single TextString. In the case of tables (i.e., a Paragraph object whose data variable contains a Table object) a separate instance of HtmlTag is created for faster processing.

package earthstones
import java.awt.*;
java.applet.*;
java.util.*;
java.io.*;
java.net.*;
class declaration public class HtmlTag extends Data
class constants Define tagId constants. Note: the getTagId() method must be updated when adding additional values are added to this list.
public static final int IGNORE = 0;
public static final int BODY = 1; <body>
public static final int BODYTAG = 2; The javascript-embedded BodyTag
public static final int P = 3; <p>
public static final int FONT = 4; <font>
public static final int B = 5; Both <b> and <strong> tags
public static final int I = 6; Both <i> and <em> tags
public static final int SUB = 7; <sub>
public static final int SUP = 8; <sup>
public static final int BASEFONT = 9; <basefont>
public static final int COMMENT = 10; <!--
public static final int A = 11; <a>
public static final int IMG = 12; <img>
public static final int HR = 13; <hr>
public static final int TEXTINSERT = 14; HTML+ <textinsert>
public static final int IMAGEINSERT = 15; HTML+ <imageinsert>
public static final int SCRIPT = 16; <script>
public static final int SPAN = 17; <span>
public static final int UL = 18; <ul>
public static final int LI = 19; <li>
public static final int BR = 20; <br>
public static final int TABLE = 21; <table>
public static final int TR = 22; <tr>
public static final int TD = 23; <td>
public static final int COND = 24; HTML+ <cond>
public static final int FORM = 25; <form>
public static final int INPUT = 26; <input>
public static final int TEXTAREA = 27; <textarea>
public static final int PREVIOUS = 28; HTML+ <previous> (currently not implemented)
public static final int NEXT = 29; HTML+ <next> (currently not implemented)
public static final int BULLET = 30; HTML+ <bullet> (currently not implemented as a separate tag)
public static final int IMAGE = 31; HTML+ <image>
public static final int ERROR = 127;
public static final int $BODY = 1 + 127; </body>
public static final int $BODYTAG = 2 + 127; The javascript-embedded BodyTag
public static final int $P = 3 + 127; </p>
public static final int $FONT = 4; + 127 </font>
public static final int $B = 5 + 127; Both </b> and </strong> tags
public static final int $I = 6 + 127; Both </i> and </em> tags
public static final int $SUB = 7 + 127; </sub>
public static final int $SUP = 8 + 127; </sup>
public static final int $COMMENT = 10 + 127; -->
public static final int $A = 11 + 127; </a>
public static final int $SCRIPT = 16 + 127; </script>
public static final int $SPAN = 17 + 127; </span>
public static final int $UL = 18 + 127; </ul>
public static final int $LI = 19 + 127; </li>
public static final int $TABLE = 21 + 127; </table>
public static final int $TR = 22 + 127; </tr>
public static final int $TD = 23 + 127; </td>
public static final int $COND = 24 + 127; HTML+ </cond>
public static final int $FORM = 25 + 127; </form>
public static final int $TEXTAREA = 27 + 127; </textarea>
In addition, many These private variables set the initial state of the HtmlTag object. They are used internally by setExtTag() and also permit communication between this method and setTagTail().
constructors HtmlTag(Container app, Document doc, DataBuffer buff, DocElement out, String src) Creates an HtmlTag object of type OUTPUT associated with program app and document doc. The object's input source is the data buffer buff whose original source is specified by the String src. This will typically be the data buffer of a Txt or Html object. The output will be written to the DocElement object out (typically a Paragraph whose initial value is set to null).
HtmlTag(Container app, Document doc, DataBuffer buff, DocElement out, Vector tgt, String src) This constructor takes the additional parameter tgt, the Data object's outputTarget. This syntax is used by HtmlTag.setExtTag() in creating another instance of HtmlTag to process a Table object in its own thread. In this case the parameter tgt is set to null to override its default assignment to document.data and thus prevent the Data.write() method from writing it again to document.data.
static methods static int getTagId(String exTag) This static method returns the tagId for
the string exTag representing an
extended tag (i.e, the HTML tag <...> itself, together with its tail--any additional text up the the next tag in the data stream). Its value is one of the tagId constants defined in this class.

Important Note: this method must be updated when adding additional values are added to this list of tagId constants defined in this class.
static String getTag(String exTag) This method takes an extended tag as a parameter and returns just the tag itself, without its tail (i.e., the <sometag name=value...> part).
static Index getTagAttrib(String tag) Parses an HTML tag into its (name=value) pairs. It will also detect attributes (e.g., NOWRAP or NOWRAP= in a <TD> tag) which can be set by stating the attributes's name only (i.e., name and value are identical). Returns an index consisting of the name-value pairs.
static Index getStyleAttrib(String str) Pparses an HTML style=styleString element into its (key: val) pairs and returns an index containing these values.
private static boolean equalsTag(String aTag, String theTag) Returns true if aTag and theTag are the same HTML tags. Necessary because HTML syntax is not case sensitive and is very forgiving about extra spaces, etc (e.g., <body> and <BoDy > are the same).
private static String getTagTail(String extTag) This method parses an extended tag, returning only its tail (i.e., any text following the tag's closing bracket >. It also translates any of HTML's special character codes set back to standard characters. Currently, the following are translated:
"&nbsp;" to " "
"&amp;" to "&")
"&lt;" to "<");
"&gt;" to ">");
"&quot;" to "\""
"&#146;" to "'")
"&#147;" to "\""
"&#148;" to "\""
methods public void read(InputStream iStr) throws IOException For this OUTPUT object, read() does nothing.
public void write(Object obj) 1a) If obj is null (there is no more data), calls document.data.setIsLoaded(true).
1b) Otherwise,
1b1) If document.plainText is set (a plain-text document), creates a new TextString object ts , sets its data variable to (String)obj, and adds ts to (Paragraph)output.
1b2) Otherwise (document is to be rendered as HTML), calls setExtTag(obj).
private void setExtTag(String extTag) With its switch statement consisting of an endless collection of case specifications, this method is the "CPU" for translating an extended tag string into the appropriate collection of DocElement objects.
The basic parsing unit is the Paragraph object, which itself is a sequence of TextString and Box objects. Each paragraph is assembled from its constituent elements, added to the document's data buffer, and then the next paragraph in the stream is tackled.
The one exception to this sequential strategy is the <table> element which will be translated into a Box subclass which itself consists of a collection of row Vector objects which consist of Paragraph cells.
Because large tables take a long time to process HtmlTag treats them in a special way: the extended tags through the end of the table are read into a table buffer tblBuff and a new (empty) Table object tbl is written to the document's data variable; then a new instance of HtmlTag is created for the table whose input variable is set to tblBuff and output variable is set to tbl. Because this new instance of HtmlTag will also run in its own thread of execution, the parent HtmlTag object is free to turn its attention back to what is next in the input stream while the child object gets busy on the table.
For this all to work properly, the Doc object that reads the Paragraph objects from document.data has to rely on the Table.show() method to be smart enough not to return until all of the table's rows have been added to the table even though it begins printing them as soon as one appears.
private void writeThePar() Called by setExtTag() and setTail() when a paragraph has been assembled and is ready to be written to document.data. Calls document.add((Paragraph)output) and resets output to null.
private DocElement getElement(String elem) Extracts and returns a DocElement (e.g., TextBox, ImageBox) buried in an extended tag of consisting of an HTML comment <!-- tag followed by the <script> tag and some javascript code and ending with the </script> and --> tags. This method is called by the loadHtml method of the Document class and implements the HTML+ javascript-embedded tags such as BodyTag and ImageInsert.
private void setTail(String tail) Sets the tail text to the appropriate data element (e.g., as the data of a new TextString object in the current paragraph versus the label of a Field object versus the hyperlinked text of a Link (<a> tag) object, etc.).
private boolean checkCond(Index cond) Implements the HTML+ <cond> tag. Returns true if the conditions specified by the (name, value) of Index cond are satified. See HTML+ documentation for an description of the variables supported.
private void setSourcePath(Index idx) If the (name-value) index idx contains an entry for the HTML "SRC" key which does not specify a fully-qualified URL, prepends the path of document.source to the value in idx. This insures than any relative paths encountered in the HTML document will be interpreted as relative to the document.
private void setImageBox(int tagId, String aTag) This method creates the appropriate ImageBox object for tagID = IMG or IMAGE and tag aTag, sets its parameters, and writes to the data buffer. Note: For javascript-wrapped images this method is not currently called. Instead, getElement() creates object and sets its parameters.

Doc. Reads the Document object's data buffer, renders each Paragraph to a user-interface panel using its flow() method, and adds the panel to the document's DocumentPanel instance.

package earthstones
import java.awt.*;
java.applet.*;
java.util.*;
java.io.*;
java.net.*;
class declaration public class Doc extends Data
constructors Doc(Container app, Document doc, DataBuffer buff) Constructs an Doc object associated with program (Applet or Application) app and Document doc whose input variable is set to buff. Calls super(app, doc, OUTPUT, buff).
methods public void read(InputStream iStr)
throws IOException
This Data object is used only for output so this method does nothing.
public void write(Object obj) 1) If obj is null, calls Web.clearCursor(Frame.WAIT_CURSOR) which will decrement Web.waitCursors and (eventually) result in the cursor being reset to the default cursor. (This action is taken in lieu of the usual Data object's procedure of setting its data buffer isLoaded variable because there is no data buffer being written in this case.
2) Otherwise, calls the paragraph's flow() method to render it to the user interface.