/* * @(#)JavaCGIBridge.java 2.00 07/18/98 * * Copyright Info: This class was written by Gunther Birznieks * gunther@clark.net having been inspired by countless other * software developers. * * Version 1.00: 08/10/97 * Version 2.00: 07/19/98 * * The second version of this software was written for * independent study under the guidance of Professor * Marty Hall as part of the Johns Hopkins University * Computer Science Master's Degree program. * * Feel free to copy, cite, reference, sample, borrow, resell * or plagiarize the contents. However, if you don't mind, * please let me know where it goes so that I can at least * watch and take part in the development of the memes. Information * wants to be free; support public domain freeware. Donations are * appreciated and will be spent on further upgrades and other public * domain programs. * */ package com.extropia.net; import java.util.Hashtable; import java.util.Enumeration; import java.util.Vector; import java.util.Observable; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.net.MalformedURLException; import java.io.ObjectOutputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.DataOutputStream; import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.io.StreamCorruptedException; import java.io.OptionalDataException; import java.applet.AppletContext; /** * This is a class that POSTS and GETS data from URLs using various * helper methods. This class also provides the capability of * timing out if the connection takes too long to transfer data * by using threads to monitor whether the data is taking too long * to transfer (implements Runnable). *

* Helper methods allow you to set up form variables, get setup * information over a URL, get raw or pre-parsed HTML data, and more. *

* The getParsedData method relies on instance variables which * tell the parser where the data begins and ends (top and bottom * separators respectively). The field and row separators inform * the parser where records and fields end. *

* The default start of data separator is <!--start of data-->\n *

* The default end of data separator is <!--end of data-->\n *

* The default field separator is | (pipe). *

* The default record separator is \n (newline). *

* If the data you are sending is likely to contain special characters * such as newlines in database fields or | symbols, you can expand * the record and field separators to be more restrictive. For example, * you might consider making the field seperator ~|~ (tilde + pipe + tilde) * if you think a stray pipe might appear somewhere. *

* Another strategy is to follow a MIME like strategy where you make * very long separators that are very unlikely to appear randomly in * binary or large database field data. An example separator string * might be "__CabbageNeck_Peter_Joe_Erik_Mark_Anthony_David_987XxX". * However, be aware that although longer separator strings provide * more security against random stray characters matching, they will * also increase the parsing time. *

* * @version 2.00, 18 Jul 1998 * @author Gunther Birznieks * @author Marty Hall * */ public class JavaCGIBridge extends Observable implements Runnable { // PUBLIC INSTANCE VARIABLES /** * SETUP indicates that the processing status is * in setup mode. This means that no communications * have been established yet. In otherwords, the programmer * is still setting up defaults. * * @see #getStatus * @see #setStatus */ public static final int SETUP = 1; /** * PROCESSING indicates that the JavaCGIBridge * object is in the middle of processing a request. * * @see #getStatus * @see #setStatus */ public static final int PROCESSING = 2; /** * IDLE indicates that the JavaCGIBridge object * has finished processing and can move on to do * something else. Usually this means that the * JavaCGIBridgePool object can give this instance * to another consumer now that it is done with * the request. * * @see #getStatus * @see #setStatus */ public static final int IDLE = 3; // PROTECTED INSTANCE VARIABLES /** * This is the vector of vectors of parsed * data. It is protected so that fetchNextRecord() can * peep it in the JavaCGIBridgeExtension class. */ protected Vector _vectorParsedData = null; /** * This is the actual CGI Timeout value in milliseconds for the * instantiated object. Notice that the default value is a static * class variable that applies across all instances of this class. * This variable, on the other hand, is the actual value the object * uses. *

* It is protected so that the other JavaCGIBridge-type classes * can also detect whether a JavaCGIBridge object has timed out. */ protected int _threadTimeOut = 10000; /** * This is a flag indicating whether the URL data was * retrieved inside the thread or not. It is protected * so that other JavaCGIBridge-type classes can * figure out if a JavaCGIBridge object has timed out. */ protected boolean _threadCompleted = true; /** * This lets us know at what point fetchNextRecord() * needs to read the next Vector. This variable is * located here so that it can be manipulated by the * communications thread as it parses Vector data * for consumption by fetchNextRecord(). */ protected int _fetchCount = 0; /** * This variable contains the base time that * the thread last received valid data. The base * time basically tells the object how much time * has past between successful communications when * compared with System.currentTimeMillis(). It is * protected so that other JavaCGIBridge-type objects * can figure out whether a JavaCGIBridge object has * timed out. */ protected long _threadBaseTime = 0; /** * This is a handle to the currently running * communications thread. It is protected * so that the JavaCGIBridgePool objects can * stop timed out threads in its clean up thread. */ protected Thread _thread; /** * This is a byte stream that contains object * serialization data in-memory. It is protected * so that it can be accessed by the serialization * API methods in JavaCGIBridgeExtension class. */ protected ByteArrayOutputStream _serialStream; /** * This is an object stream that contains * a decorator for the byte stream which contains * serialized objects for POSTing. It is protected * so that its contents can be accessed by * the serialization API methods in the * JavaCGIBridgeExtension class. */ protected ObjectOutputStream _serialObjectStream; // PRIVATE INSTANCE VARIABLES /** * The field separator. When a CGI script or HTML file * returns data, then the getParsedData() method will * know how to separate fields by looking at this variable. * * The default value is "|" (pipe). This is * considered sufficiently unlikely to appear inside of actual * field data that it is a pretty good field separator to parse * on. If the user of this class needs a different separator, it * may be overridden by calling the appropriate method. */ private byte [] _fieldSeparator; /** * The record separator. When a CGI script or HTML file * returns data, then the getParsedData() method will * know how to separate returned rows by looking at this variable. * * The default value is "\n" (newline). * This is considered sufficiently unlikely to appear inside of * actual row data that it is a pretty good row separator to parse * on. If the user of this class needs a different separator, it * may be overridden by calling the appropriate method. */ private byte [] _recordSeparator; /** * The top of data separator. When a CGI script or HTML file * returns data, then the getParsedData() method will * determine when to start parsing data by encountering this * separator. * * The default value is "\n" including a * a newline. That is, a newline is generally expected to follow * this separator. */ private byte [] _startDataSeparator; /** * The bottom of data separator. When a CGI script or HTML file * returns data, then the getParsedData() method will * determine when to stop parsing data by encountering this * separator. * * The default value is "\n" including * a newline. That is, a newline is generally expected to follow * this separator. */ private byte [] _endDataSeparator; /** * The URL That data is retrieved from. This is an instance * variable rather than a parameter because the data retrieval * is done from a launched thread which gets no parameters. */ private URL _threadURL = null; /** * The HTML form data for the URL that data is retrieved from. * This is an instance variable rather than a parameter because * the data retrieval is done from a launched thread which gets * no parameters. */ private Hashtable _threadFormVar = null; /** * This is the returned URL data. It is an instance variable because * the run() method of the thread cannot explicitly return data. */ private byte [] _threadRawData = null; /** * _parseDataAsVector is a flag letting the HTTP parser know to * parse data on the fly as it is coming in. */ private boolean _parseDataAsVector = false; /** * _parseAsRaw is a flag that indicates whether * the Vector of Vectors will contain fields as * traditional Java Strings (false, the default) or * raw binary byte arrays (true). */ private boolean _parseAsRaw = false; /** * _threadIdleAtEnd sets the object in the * IDLE state automatically when a callOneWay() * is used to launch an HTTP session. This * value is generally set to true by default, but * it will be set to false if the user calls the * callOneWay() method by telling it that they * intend to call fetchNextRecord(). The reason * this is done is that it is possible, in a multi * threaded environment that fetchNextRecord() might * be called after the whole HTTP session has * finished. In this case, another thread might * easily reuse the JavaCGIBridge object in the IDLE * state before fetchNextRecord() was called. Therefore, * it is imperative that if you intend to use fetchNextRecord() * that you tell the callOneWay() function you intend to * do so. */ private boolean _threadIdleAtEnd = true; /** * _threadOneWay tells the run() method whether * it was launched from an asynchronous method * such as callOneWay() or a synchronous method * such as getRawData(). _threadOneWay == true * if it was launched from an asynchronous method. */ private boolean _threadOneWay = false; /** * This is the number of parsed lines before * notifying observers of the latest batch * of parsed Vector records. The default is 0 * (no notification). * * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ private int _parsedNotifyInterval = 0; /** * This is the number of raw data bytes (usually * HTML chars) before notifying observers of the * latest batch of raw data. The default is * 0 (no notification). * * @see #getRawNotifyInterval * @see #setRawNotifyInterval */ private int _rawNotifyInterval = 0; /** * This integer holds the current processing status * of the class. Its value is either SETUP (1), * PROCESSING (2), or IDLE (3). */ private int _processingStatus = SETUP; /** * Constructs the object with new separator values */ public JavaCGIBridge(String field, String record, String startData, String endData) { _initJavaCGIBridge(field,record,startData,endData); } /** * Constructs the object with no initialization. This is the default * (empty) constructor. */ public JavaCGIBridge() { _initJavaCGIBridge("|","\n","\n","\n"); } // Empty constructor /** * Adds a form variable, value pair to the passed Hashtable. * * @param ht the Hashtable that contains the form variable/value pairs * @param formKey the String that contains the form variable to add * @param formValue the String that contains the form value to add */ public void addFormValue(Hashtable ht, String formKey, String formValue) { Vector vValues = null; if (formValue != null && formValue.length() > 0) { if (ht.containsKey(formKey)) { vValues = (Vector)ht.get(formKey); } else { vValues = new Vector(); } vValues.addElement(formValue); ht.put(formKey, vValues); } } // End of addFormValue /** * Takes the parsed data returned from the getParsedData method * and changes it to a Hashtable of key, value pairs where the first * Vector entry of each Vector record is the key and the rest of the * second Vector entry for each record is the value of the Hashtable. * * @param vectorOfVectors the Vector of Vectors for the parsed data * @return Hashtable containing converted variable/value pairs * @see #getParsedData */ public Hashtable getKeyValuePairs(Vector vectorOfVectors) { Hashtable h = new Hashtable(); Vector v = null; for (Enumeration e = vectorOfVectors.elements(); e.hasMoreElements();) { v = (Vector)e.nextElement(); h.put((String)v.elementAt(0), (String)v.elementAt(1)); } return h; } // End of getKeyValuePairs /** * Returns parsed data in the form of a Vector of Vectors containing * the returned fields inside of a Vector of returned rows. * * @param u URL to get parsed data from. * @return Vector (records) of vectors (fields) of parsed data * @exception JavaCGIBridgeTimeOutException If the retrieval times out * @see #getRawData * @see #callOneWay * @see #getParseAsRaw * @see #setParseAsRaw * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ public Vector getParsedData(URL u) throws JavaCGIBridgeTimeOutException { return (getParsedData(u, null)); } /** * Returns parsed data in the form of a Vector of Vectors containing * the returned fields inside of a Vector of returned rows. This form * POSTs the HTML Form variable data to the URL. * * @param u URL to get parsed data from. * @param ht Hashtable contains form variables to POST * @return Vector (records) of vectors (fields) of parsed data * @exception JavaCGIBridgeTimeOutException If the retrieval times out * @see #getRawData * @see #callOneWay * @see #getParseAsRaw * @see #setParseAsRaw * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ public Vector getParsedData(URL u, Hashtable ht) throws JavaCGIBridgeTimeOutException { // getParsedData calls getRawData to obtain // the actual HTML text // Notice that we turn on the flag to parse // vector data inside the getRawData block // // We need to do this in order to provide a // mechanism for returning partial results to // an observer. // _parseDataAsVector = true; _getData(u,ht); _parseDataAsVector = false; // NOTE: We have to save the vector parsed data // because as soon as we set the object to the IDLE // state, another thread could start using the JavaCGIBridge Vector v = _vectorParsedData; setStatus(IDLE); return v; } /** * Returns raw HTML data as a String from the passed URL. * * @param u URL to get raw HTML from. * @return String containing plain HTML text * @exception JavaCGIBridgeTimeOutException If the retrieval times out * @see #getParsedData * @see #callOneWay * @see #getRawNotifyInterval * @see #setRawNotifyInterval */ public byte [] getRawData(URL u) throws JavaCGIBridgeTimeOutException { return (getRawData(u,null)); } /** * Returns raw HTML data as a String from the passed URL and list * of Form variable/value pairs stored in a Hashtable. This form * POSTs the HTML Form variable data to the URL. * * @param u URL to get raw HTML from. * @param ht Hashtable contains form variables to POST * @return String containing plain HTML text * @exception JavaCGIBridgeTimeOutException If the retrieval times out * @see #getParsedData * @see #callOneWay * @see #getRawNotifyInterval * @see #setRawNotifyInterval */ public byte [] getRawData(URL u, Hashtable ht) throws JavaCGIBridgeTimeOutException { _getData(u,ht); // NOTE: We have to save the vector parsed data // because as soon as we set the object to the IDLE // state, another thread could start using the JavaCGIBridge byte [] b = _threadRawData; setStatus(IDLE); return b; } // end of getRawData /** * Calls the URL but returns immediately. This is * called a ONEWAY operation. This method is used * in one of three circumstances. *

* [1] You want to "fire and forget" an operation such * as an update to a file or database on the web server * without worrying about a return code or whether the * operation even succedded. *

* [2] You want to set up an observer interface to * the bridge to notify yourself as data comes in * instead of blocking the whole program while waiting * for the data. *

* [3] You want to call fetchNextRecord method in * the JavaCGIBridgeExtension class. Basically, the * callOneWay() operation returns immediately so that * it leaves your program free to loop through the * fetchNextRecord() method. Note that if you use * callOneWay for this purpose, it is recommended that * you call the version where you set "fetchData" equal * to true so that the Object is not set to the IDLE * state prematurely. This is discussed in further * detail in the documentation for fetchNextRecord() * in the JavaCGIBridgeExtension class. * * @param u URL to get raw HTML from. * @see #getRawData * @see #getParsedData * @see #getRawNotifyInterval * @see #setRawNotifyInterval * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ public void callOneWay(URL u) { callOneWay(u,null); } /** * Calls the URL but returns immediately. This is * called a ONEWAY operation. This method is used * in one of three circumstances. *

* [1] You want to "fire and forget" an operation such * as an update to a file or database on the web server * without worrying about a return code or whether the * operation even succedded. *

* [2] You want to set up an observer interface to * the bridge to notify yourself as data comes in * instead of blocking the whole program while waiting * for the data. *

* [3] You want to call fetchNextRecord method in * the JavaCGIBridgeExtension class. Basically, the * callOneWay() operation returns immediately so that * it leaves your program free to loop through the * fetchNextRecord() method. Note that if you use * callOneWay for this purpose, it is recommended that * you call the version where you set "fetchData" equal * to true so that the Object is not set to the IDLE * state prematurely. This is discussed in further * detail in the documentation for fetchNextRecord() * in the JavaCGIBridgeExtension class. * * @param u URL to get raw HTML from. * @param fetchData Set to true if you intend to * use the fetchNextRecord() method. * This avoids the thread automatically * setting the state of the object to * IDLE when the thread completes. This * is necessary because it is possible that * fetchNextRecord has not completed * fetching all the records by the time * the communications thread ends. * @see #getRawData * @see #getParsedData * @see #getRawNotifyInterval * @see #setRawNotifyInterval * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ public void callOneWay(URL u, boolean fetchData) { callOneWay(u,null,fetchData); } /** * Calls the URL but returns immediately. This is * called a ONEWAY operation. This method is used * in one of three circumstances. *

* [1] You want to "fire and forget" an operation such * as an update to a file or database on the web server * without worrying about a return code or whether the * operation even succedded. *

* [2] You want to set up an observer interface to * the bridge to notify yourself as data comes in * instead of blocking the whole program while waiting * for the data. *

* [3] You want to call fetchNextRecord method in * the JavaCGIBridgeExtension class. Basically, the * callOneWay() operation returns immediately so that * it leaves your program free to loop through the * fetchNextRecord() method. Note that if you use * callOneWay for this purpose, it is recommended that * you call the version where you set "fetchData" equal * to true so that the Object is not set to the IDLE * state prematurely. This is discussed in further * detail in the documentation for fetchNextRecord() * in the JavaCGIBridgeExtension class. * * @param u URL to get raw HTML from. * @param ht Hashtable contains form variables to POST * @see #getRawData * @see #getParsedData * @see #getRawNotifyInterval * @see #setRawNotifyInterval * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ public void callOneWay(URL u, Hashtable ht) { callOneWay(u,ht,false); } /** * Calls the URL but returns immediately. This is * called a ONEWAY operation. This method is used * in one of three circumstances. *

* [1] You want to "fire and forget" an operation such * as an update to a file or database on the web server * without worrying about a return code or whether the * operation even succedded. *

* [2] You want to set up an observer interface to * the bridge to notify yourself as data comes in * instead of blocking the whole program while waiting * for the data. *

* [3] You want to call fetchNextRecord method in * the JavaCGIBridgeExtension class. Basically, the * callOneWay() operation returns immediately so that * it leaves your program free to loop through the * fetchNextRecord() method. Note that if you use * callOneWay for this purpose, it is recommended that * you call the version where you set "fetchData" equal * to true so that the Object is not set to the IDLE * state prematurely. This is discussed in further * detail in the documentation for fetchNextRecord() * in the JavaCGIBridgeExtension class. * * @param u URL to get raw HTML from. * @param ht Hashtable contains form variables to POST * @param fetchData Set to true if you intend to * use the fetchNextRecord() method. * This avoids the thread automatically * setting the state of the object to * IDLE when the thread completes. This * is necessary because it is possible that * fetchNextRecord has not completed * fetching all the records by the time * the communications thread ends. * @see #getRawData * @see #getParsedData * @see #getRawNotifyInterval * @see #setRawNotifyInterval * @see #getParsedNotifyInterval * @see #setParsedNotifyInterval */ public void callOneWay(URL u, Hashtable ht, boolean fetchData) { _threadURL = u; _threadFormVar = ht; _threadBaseTime = System.currentTimeMillis(); // We want to make sure that // if we are setting up for fetching // records that the data is parsed // and the JavaCGIBridge is not set // to IDLE until the last record is fetched. _parseDataAsVector = fetchData || (_parsedNotifyInterval != 0); _threadIdleAtEnd = !fetchData; _threadOneWay = true; _thread= new Thread(this); _threadCompleted = false; _thread.start(); } /** * Returns the actual communication time out in milliseconds * for the object. The default is 10 seconds. * * When the object retrieves data from a URL, it must get * the data within timeout milliseconds or a * JavaCGIBridgeTimeOutException is thrown. * * @return communication time out in milliseconds * @see #setTimeOut */ public int getTimeOut() { return _threadTimeOut; } /** * Sets the actual communication time out in milliseconds * for the object. The default is 10 seconds. * * When the object retrieves data from a URL, it must get * the data within timeout milliseconds or a * JavaCGIBridgeTimeOutException is thrown. * * @param t communication time out in milliseconds * @see #getTimeOut */ public void setTimeOut(int t) { _threadTimeOut = t; } /** * Sets the field separator for the object. When getParsedData * method is called, the object uses the field separator to determine * where fields in a returned record of the raw HTML result set * begin and end. * * @param s String containing new delimiting separator * @see #getParsedData * @see #getFieldSeparator */ public void setFieldSeparator(String s) { _fieldSeparator = _getBytes(s); } /** * Returns the field separator for the object. When getParsedData * method is called, the object uses the field separator to determine * where fields in a returned record of the raw HTML result set * begin and end. * * @return Separator string * @see #getParsedData * @see #setFieldSeparator */ public String getFieldSeparator() { return new String(_fieldSeparator, 0); } /** * Sets the record separator for the object. When getParsedData * method is called, the object uses the record separator to determine * where records/rows of the raw HTML result set * begin and end. * * @param s String containing new delimiting separator * @see #getParsedData * @see #getRecordSeparator */ public void setRecordSeparator(String s) { _recordSeparator = _getBytes(s); } /** * Returns the record separator for the object. When getParsedData * method is called, the object uses the record separator to determine * where records/rows of the raw HTML result set * begin and end. * * @return Separator string * @see #getParsedData * @see #setRecordSeparator */ public String getRecordSeparator() { return new String(_recordSeparator, 0); } /** * Sets the start of data separator for the object. When getParsedData * method is called, the object uses the start of data separator to determine * where the rows of data inside the raw HTML output actually begin. * * @param s String containing new delimiting separator * @see #getParsedData * @see #getStartDataSeparator */ public void setStartDataSeparator(String s) { _startDataSeparator = _getBytes(s); } /** * Returns the start of data separator for the object. When getParsedData * method is called, the object uses the start of data separator to determine * where the rows of data inside the raw HTML output actually begin. * * @return Separator string * @see #getParsedData * @see #setStartDataSeparator */ public String getStartDataSeparator() { return new String(_startDataSeparator, 0); } /** * Sets the end of data separator for the object. When getParsedData * method is called, the object uses the end of data separator to determine * where the rows of data inside the raw HTML output actually end. * * @param s String containing new delimiting separator * @see #getParsedData * @see #getEndDataSeparator */ public void setEndDataSeparator(String s) { _endDataSeparator = _getBytes(s); } /** * Returns the end of data separator for the object. When getParsedData * method is called, the object uses the end of data separator to determine * where the rows of data inside the raw HTML output actually end. * * @return Separator string * @see #getParsedData * @see #setEndDataSeparator */ public String getEndDataSeparator() { return new String(_endDataSeparator, 0); } /** * Returns an integer indicating the number of records which will * trigger a notification to observers with the contents of what * has been parsed so far. When this is set to a positive number, * it will also notify when the records have finished being parsed * at the end of the HTTP response. When this is set to a negative * number, no periodic notifications will be sent, however one will * be sent at the end of the HTTP response. * * @return int Number of records between parse notifications. Set to 0 * to turn off parsing notification, * Set to a negative number to * only send notifications at the end. * @see #setParsedNotifyInterval */ public int getParsedNotifyInterval() { return _parsedNotifyInterval; } /** * Sets an integer indicating the number of records which will * trigger a notification to observers with the contents of what * has been parsed so far. When this is set to a positive number, * it will also notify when the records have finished being parsed * at the end of the HTTP response. When this is set to a negative * number, no periodic notifications will be sent, however one will * be sent at the end of the HTTP response. * * @param n Number of records between parse notifications. Set to 0 * to turn off parsing notification, * Set to a negative number to * only send notifications at the end. * @see #getParsedNotifyInterval */ public void setParsedNotifyInterval(int n) { _parsedNotifyInterval = n; } /** * Returns an integer indicating the number of raw content bytes * from the HTTP response which will * trigger a notification to observers with the contents of what * has been read so far. When this is set to a positive number, * it will also notify when the HTTP response has finished. * When this is set to a negative * number, no periodic notifications will be sent, however one will * be sent at the end of the HTTP response. * * @return int Number of bytes between notifications. Set to 0 * to turn off notification after lines of HTML * sent in the HTTP response, * Set to a negative number to * only send notifications at the end. * @see #setRawNotifyInterval */ public int getRawNotifyInterval() { return _rawNotifyInterval; } /** * Sets an integer indicating the number of raw content bytes * from the HTTP response which will * trigger a notification to observers with the contents of what * has been read so far. When this is set to a positive number, * it will also notify when the HTTP response has finished. * When this is set to a negative * number, no periodic notifications will be sent, however one will * be sent at the end of the HTTP response. * * @param n Number of bytes between notifications. Set to 0 * to turn off notification after bytes of HTML * sent in the HTTP response, * Set to a negative number to * only send notifications at the end. * @see #getRawNotifyInterval */ public void setRawNotifyInterval(int n) { _rawNotifyInterval = n; } /** * Returns true or false depending on * whether the JavaCGIBridge will parse the fields * in the HTTP response as Strings (default) or * as raw data byte arrays. Use byte arrays if you public void setRawNotifyInterval(int n) { _rawNotifyInterval = n; } /** * Returns true or false depending on * whether the JavaCGIBridge will parse the fields * in the HTTP response as Strings (default) or * as raw data byte arrays. Use byte arrays if you * will be transferring binary data such as a jpeg * or gif image. * * @return boolean Flag indicating parsing as * raw byte array or as Strings * @see #setParseAsRaw */ public boolean getParseAsRaw() { return _parseAsRaw; } /** * Sets the flag that indicates whether the * JavaCGIBridge will parse the HTTP response * data as raw byte array or as String (default). * * @param b Flag indicating true or false * @see #getParseAsRaw */ public void setParseAsRaw(boolean b) { _parseAsRaw = b; } /** * Returns the processing status of the JavaCGIBridge * objects. It will be equal to SETUP (1), PROCESSING (2), * or IDLE (3) public static class variables. * * @return int Status code * @see #setStatus */ public int getStatus() { return _processingStatus; } // end of getStatus /** * Sets the processing status of the JavaCGIBridge * object. You will set it to SETUP (1), PROCESSING (2), * or IDLE (3) public static class variables. * * @param status Status code * @see #getStatus */ public void setStatus(int status) { if (status < 1 || status > 3) return; _processingStatus = status; } // end of setStatus /** * This run thread asynchronously POSTs and GETs data from * a URL and places the contents into the _threadRawData variable. * * Since Threads do not return or pass parameter values, instance * variables in this object are used to maintain state. This method * is only public so that the Thread class can launch the thread. * * @see #getRawData */ public void run() { try { _threadRawData = _getHttpRequestInThread( _threadURL, _threadFormVar); } catch (JavaCGIBridgeTimeOutException e) { e.printStackTrace(); System.out.println("JavaCGIBridgeTimeOutException thrown!"); } finally { _threadCompleted = true; // set completed flag synchronized(this) { notifyAll(); } // ends the wait() for thread to end in getRawData if (_threadOneWay && _threadIdleAtEnd) { setStatus(IDLE); _threadOneWay = false; _threadIdleAtEnd = false; _parseDataAsVector = false; } } } // end of run -- The thread runs /** * Returns the form variables inside the hashtable as a * URL encoded string of parameters for a CGI based program * to process. * * @param ht Hashtable containing form variables * @return URLencoded string of HTML form variables & values * @see #addFormValue */ public String getURLEncodedHashtable(Hashtable ht) { StringBuffer encodedString = null; Vector vFormValues = null; // First, we enumerate through the keys (Form variables) for (Enumeration eKeys = ht.keys() ; eKeys.hasMoreElements() ;) { String formVariable = (String)eKeys.nextElement(); vFormValues = (Vector)ht.get(formVariable); // Now, we have to enumerate through the values for the form variables. // // NOTE: It IS entirely possible that a form variable has MANY values // to simulate events such as multiple checkboxes or multiple select