Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/enhydra/httpServerTest/common/HttpResponseObject.java


1   /*
2    * Enhydra Java Application Server Project
3    * 
4    * The contents of this file are subject to the Enhydra Public License
5    * Version 1.1 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License on
7    * the Enhydra web site ( http://www.enhydra.org/ ).
8    * 
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
11   * the License for the specific terms governing rights and limitations
12   * under the License.
13   * 
14   * The Initial Developer of the Enhydra Application Server is Lutris
15   * Technologies, Inc. The Enhydra Application Server and portions created
16   * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17   * All Rights Reserved.
18   * 
19   * Contributor(s):
20   * 
21   * $Id: HttpResponseObject.java,v 1.3.2.1.2.1 2000/10/19 17:59:08 jasona Exp $
22   */
23  
24  package org.enhydra.httpServerTest.common;
25  
26  import java.util.Hashtable;
27  import java.util.Enumeration;
28  import java.util.Vector;
29  import java.util.StringTokenizer;
30  
31  /**
32   * This class is the data structure that is shared between the client and 
33   * server tests.  The life cycle of this class begins when a client thread's
34   * run() method is invoked.  The first step in each of the 
35   * SingleUserGetRequestThread and SingleUserPostRequestThread is to initialize
36   * a golden response object of this type from the thread's supplied 
37   * configuration data.  On success of this initialization, each of these 
38   * threads construct an HTTP request also based on its configuration data.
39   * The request is sent to the server which then generates a new object of
40   * this type populated with all the request information sent from the client.
41   * This object's toString() method is then called by the server and the 
42   * output, a valid XML structure based on the data populated by the server and
43   * validated againt HttpResponseObject.dtd, is returned to the client.  The
44   * client then parses the response (the XML structure) and does an equal()
45   * comparison between the golden response object initialized earlier and the
46   * resulting object (from parsing the XML response).  If these objects are
47   * equal, the process begins again starting with issueing a new request.  If
48   * these objects are not equal, an assertion is logged by the client thread
49   * and, again, the process is repeated with issueing a new request.
50   *
51   * This structure represents the data returned from the servlet request api
52   * and the relationship between its getter methods and the data members held
53   * here pretty much match one-to-one.
54   * @see org.enhydra.httpServerTest.common.HttpResponseObjectParser
55   * @see org.enhydra.httpServerTest.server.application.presentation.BasicTest
56   * @see org.enhydra.httpServerTest.client.BaseTestThread
57   * @see org.enhydra.httpServerTest.client.SingleUserGetRequestThread
58   * @see org.enhydra.httpServerTest.client.SingleUserPostRequestThread
59   * 
60   * @author Mike Ward
61   **/
62  public class HttpResponseObject {
63  
64      /**
65       * Static XML header tag.
66       * @see HttpResponseObject.dtd for details
67       **/
68      public static final String XML_HEADER_STRING = "<?xml version=\"1.0\"?>";
69  
70      /**
71       * This holds the location of the DTD used to validate the XML structure
72       * returned by this class's toString() method.  This value should be set
73       * before calling toString().
74       **/
75      public static String HTTP_RESPONSE_OBJECT_DTD = null;
76  
77      /**
78       * Static XML document type tag.  This is the DTD reference used for 
79       * validity checks.
80       * @see HttpResponseObject.dtd for details
81       **/
82      public static String XML_DOCTYPE_STRING_BEGIN = 
83    "<!DOCTYPE HttpResponseObject SYSTEM \"";
84      public static String XML_DOCTYPE_STRING_END = "\">";
85  
86      /**
87       * Thes are common syntax tags used for constructing XML elements.
88       * @see HttpResponseObject.dtd for details
89       **/
90      public static final String BEGIN_ELEMENT_TAG = "<";
91      public static final String END_ELEMENT_TAG = "</";
92      public static final String END_EMPTY_ELEMENT_TAG = "/>";
93      public static final String END_PCDATA_ELEMENT_TAG = ">";
94  
95      /**
96       * Static HttpResponseObject element tag.
97       * @see HttpResponseObject.dtd for details
98       **/
99      public static final String HTTP_RESPONSE_OBJ_ELEMENT = 
100   "HttpResponseObject";
101 
102     /**
103      * Static HttpRequestIngo element tag and its attributes.
104      * @see HttpResponseObject.dtd for details
105      **/
106     public static final String HTTP_REQUEST_INFO_ELEMENT = 
107   "HttpRequestInfo";
108     public static final String HTTP_REQUEST_INFO_AUTH_TYPE_ATTR = 
109   "authType";
110     public static final String HTTP_REQUEST_INFO_METHOD_ATTR = 
111   "method";
112     public static final String HTTP_REQUEST_INFO_PATH_INFO_ATTR = 
113   "pathInfo";
114     public static final String HTTP_REQUEST_INFO_PATH_TRANSLATED_ATTR = 
115   "pathTranslated";
116     public static final String HTTP_REQUEST_INFO_QUERY_STRING_ATTR = 
117   "queryString";
118     public static final String HTTP_REQUEST_INFO_REMOTE_USER_ATTR = 
119   "remoteUser";
120     public static final String HTTP_REQUEST_INFO_REQUEST_URI_ATTR = 
121   "requestURI";
122     public static final String HTTP_REQUEST_INFO_SERVLET_PATH_ATTR = 
123   "servletPath";
124     public static final String HTTP_REQUEST_INFO_SESSION_ATTR = 
125   "session";
126     public static final String HTTP_REQUEST_INFO_SESSION_ID_FROM_COOKIE_ATTR = 
127   "sessionIdFromCookie";
128     public static final String HTTP_REQUEST_INFO_SESSION_ID_FROM_URL_ATTR =
129   "sessionIdFromURL";
130     public static final String HTTP_REQUEST_INFO_SESSION_ID_INVALID_ATTR = 
131   "sessionIdInvalid";
132 
133     /**
134      * Static CgiParam element tag and its attributes.
135      * @see HttpResponseObject.dtd for details
136      **/
137     public static final String CGI_PARAM_ELEMENT = "CgiParam";
138     public static final String CGI_PARAM_NAME_ATTR = "name";
139     public static final String CGI_PARAM_VALUE_ATTR = "value";
140 
141     /**
142      * Static CgiArg element tag and its attributes.
143      * @see HttpResponseObject.dtd for details
144      **/
145     public static final String CGI_ARG_ELEMENT = "CgiArg";
146     public static final String CGI_ARG_NAME_ATTR = "name";
147     public static final String CGI_ARG_VALUE_ATTR = "value";
148 
149     /**
150      * Static Header element tag and its attributes.
151      * @see HttpResponseObject.dtd for details
152      **/
153     public static final String HEADER_ELEMENT = "Header";
154     public static final String HEADER_NAME_ATTR = "name";
155     public static final String HEADER_VALUE_ATTR = "value";
156 
157     /**
158      * Static Cookie element tag and its attributes.
159      * @see HttpResponseObject.dtd for details
160      **/
161     public static final String COOKIE_ELEMENT = "Cookie";
162     public static final String COOKIE_NAME_ATTR = "name";
163     public static final String COOKIE_VALUE_ATTR = "value";
164 
165     /**
166      * Static FileUpload element tag and its attributes.
167      * @see HttpResponseObject.dtd for details
168      **/
169     public static final String FILE_UPLOAD_ELEMENT = "FileUpload";
170     public static final String FILE_UPLOAD_MD5_HASH_KEY_ATTR = "md5HashKey";
171 
172     /**
173      * Static default or implied values for element attributes.
174      * @see HttpResponseObject.dtd for details
175      **/
176     public static final String DEFAULT_SESSION = null;
177 
178     public static final boolean DEFAULT_SEESION_ID_FROM_COOKIE = false;
179     public static final boolean DEFAULT_SESSION_ID_FROM_URL = false;
180     public static final boolean DEFAULT_SESSION_ID_INVALID = false;
181 
182     /**
183      * Response object variables.
184      **/
185     public String authType = null;
186     public String method = null;
187     public String pathInfo = null;
188     public String pathTranslated = null;
189     public String queryString = null;
190     public String remoteUser = null;
191     public String requestURI = null;
192     public String servletPath = null;
193     public String session = DEFAULT_SESSION;
194     public boolean sessionIdFromCookie = DEFAULT_SEESION_ID_FROM_COOKIE;
195     public boolean sessionIdFromURL = DEFAULT_SESSION_ID_FROM_URL;
196     public boolean sessionIdInvalid = DEFAULT_SESSION_ID_INVALID;
197 
198     public Hashtable cgiParams = new Hashtable();
199     public Hashtable cgiArgs = new Hashtable();
200     public Hashtable headers = new Hashtable();
201     public Hashtable cookies = new Hashtable();
202     public Vector md5HashKey = new Vector();
203 
204 
205     /**
206      * This function overrides the default toString method to generate a 
207      * valid XML structure based on data held within this object.  The
208      * generated structure is valid against HttpResponseObject.dtd and
209      * is the stream that is sent back from the server to the client.
210      *
211      * @return String
212      *         The XML string representing this object.
213      **/
214     public String toString() {
215   StringBuffer xmlBuffer = new StringBuffer();
216   
217   String[] cgiParamStrings = getCgiParamStrings();
218   for (int i = 0; i < cgiParamStrings.length; i++) {
219       xmlBuffer.append(cgiParamStrings[i]);
220   }
221 
222   String[] cgiArgStrings = getCgiArgStrings();
223   for (int i = 0; i < cgiArgStrings.length; i++) {
224       xmlBuffer.append(cgiArgStrings[i]);
225   }
226 
227   String[] headerStrings = getHeaderStrings();
228   for (int i = 0; i < headerStrings.length; i++) {
229       xmlBuffer.append(headerStrings[i]);
230   }
231 
232   String[] cookieStrings = getCookieStrings();
233   for (int i = 0; i < cookieStrings.length; i++) {
234       xmlBuffer.append(cookieStrings[i]);
235   }
236 
237   String[] md5Strings = getFileUploadStrings();
238   for (int i = 0; i < md5Strings.length; i++) {
239       xmlBuffer.append(md5Strings[i]);
240   }
241 
242   String[] httpRequestInfoStrings = getHttpRequestInfoStrings();
243   xmlBuffer.insert(0, httpRequestInfoStrings[0]);
244   xmlBuffer.append(httpRequestInfoStrings[1]);
245 
246   String[] httpResponseObjectStrings = getHttpResponseObjectStrings();
247   xmlBuffer.insert(0, httpResponseObjectStrings[0]);
248   xmlBuffer.append(httpResponseObjectStrings[1]);
249 
250   xmlBuffer.insert(0, XML_DOCTYPE_STRING_END);
251   xmlBuffer.insert(0, HTTP_RESPONSE_OBJECT_DTD);
252   xmlBuffer.insert(0, XML_DOCTYPE_STRING_BEGIN);
253 
254   xmlBuffer.insert(0, XML_HEADER_STRING);
255 
256   return xmlBuffer.toString();
257     }
258 
259     /**
260      * This function overrides the default equals method to provide a detailed
261      * comparison of each data member held within this object.  If any 
262      * differences are found, a 'false' value is immediately returned.  If
263      * all data members are determined to be equal, a 'true' value is
264      * returned.
265      *
266      * @param object
267      *        The object to compare against.
268      * @return boolean
269      *         The equality status of all data members.
270      **/
271     public boolean equals(Object object) {
272 
273   if (object == null) {
274       return false;
275   }
276 
277   if (!(object instanceof HttpResponseObject)) {
278       return false;
279   }
280 
281   HttpResponseObject httpResponseObject = (HttpResponseObject)object;
282   
283   if (!testStringNulls(authType, httpResponseObject.authType)) {
284       if (authType == null ||
285     httpResponseObject.authType == null ||
286     !authType.equals(httpResponseObject.authType)) {
287     return false;
288       }
289   }
290   if (!testStringNulls(method, httpResponseObject.method)) {
291       if (method == null ||
292     httpResponseObject.method == null ||
293     !method.equals(httpResponseObject.method)) {
294     return false;
295       }
296   }
297   if (!testStringNulls(pathInfo, httpResponseObject.pathInfo)) {
298       if (pathInfo == null ||
299     httpResponseObject.pathInfo == null ||
300     !testPathInfo(pathInfo, httpResponseObject.pathInfo)) {
301     return false;
302       }
303   }
304   if (!testStringNulls(pathTranslated, httpResponseObject.pathTranslated)) {
305       if (pathTranslated == null ||
306     httpResponseObject.pathTranslated == null ||
307     !pathTranslated.equals(httpResponseObject.pathTranslated)) {
308     return false;
309       }
310   }
311   if (!testStringNulls(queryString, httpResponseObject.queryString)) {
312       if (queryString == null ||
313     httpResponseObject.queryString == null ||
314     !testQueryString(queryString, 
315          httpResponseObject.queryString)) {
316     return false;
317       }
318   }
319   if (!testStringNulls(remoteUser, httpResponseObject.remoteUser)) {
320       if (remoteUser == null ||
321     httpResponseObject.remoteUser == null ||
322     !remoteUser.equals(httpResponseObject.remoteUser)) {
323     return false;
324       }
325   }
326   if (!testStringNulls(requestURI, httpResponseObject.requestURI)) {
327       if (requestURI == null ||
328     httpResponseObject.requestURI == null ||
329     !testRequestURI(requestURI, httpResponseObject.requestURI)) {
330     return false;
331       }
332   }
333   if (!testStringNulls(servletPath, httpResponseObject.servletPath)) {
334       if (servletPath == null ||
335     httpResponseObject.servletPath == null ||
336     !servletPath.equals(httpResponseObject.servletPath)) {
337     return false;
338       }
339   }
340   if (!testStringNulls(session, httpResponseObject.session)) {
341       if (session == null ||
342     httpResponseObject.session == null ||
343     !session.equals(httpResponseObject.session)) {
344     return false;
345       }
346   }
347   if (!sessionIdFromCookie == httpResponseObject.sessionIdFromCookie) {
348       return false;
349   }
350   if (!sessionIdFromURL == httpResponseObject.sessionIdFromURL) {
351       return false;
352   }
353   if (!sessionIdInvalid == httpResponseObject.sessionIdInvalid) {
354       return false;
355   }
356   if (!(cgiParams == null && httpResponseObject.cgiParams == null)) {
357       if (!testHashtables(cgiParams, httpResponseObject.cgiParams)) {
358     return false;
359       }
360   }
361   if (!(cgiArgs == null && httpResponseObject.cgiArgs == null)) {
362       if (!testHashtables(cgiArgs, httpResponseObject.cgiArgs)) {
363     return false;
364       }
365   }
366   if (!(headers == null && httpResponseObject.headers == null)) {
367       if (!testHashtables(headers, httpResponseObject.headers)) {
368     return false;
369       }
370   }
371   if (!(cookies == null && httpResponseObject.cookies == null)) {
372       if (!testHashtables(cookies, httpResponseObject.cookies)) {
373     return false;
374       }
375   }
376   if (!(md5HashKey == null && httpResponseObject.md5HashKey == null)) {
377       if (!testVectors(md5HashKey, httpResponseObject.md5HashKey)) {
378     return false;
379       }
380   }
381   return true;
382     }
383 
384     /**
385      * This is a convenience function fro testing the equality of
386      * two possibly null strings.  This function considers all strings
387      * actaully equal to null, empty strings, and strings holding the value
388      * 'null' to be considered null.  The purpose of this function is to 
389      * deal with the case that a string, when sent over an http connection,
390      * often gets the string value of 'null' applied to it when parsed by
391      * the SAX parser.
392      *
393      * @param string1
394      *        The first string used for testing.
395      * @param string2
396      *        The second string used for testing.
397      * @return boolean
398      *         The result of testing the two strings for nulls.  Returns true
399      *         if both strings are determined to be null.
400      **/
401     public boolean testStringNulls(String string1,
402            String string2) {
403   if (string1 == null &&
404       string2 == null) {
405       return true;
406   } else if (string1 == null &&
407        (string2.equals("null") ||
408         string2.equals(""))) {
409       return true;
410   } else if (string2 == null &&
411        (string1.equals("null") ||
412         string1.equals(""))) {
413       return true;
414   } else {
415       return false;
416   }
417     }
418 
419     /**
420      * This is a conviencce function to test the equality of two hashtables.
421      * This function will consider a null hashtable and an empty hashtable
422      * equal.  If both the supplied hashtables are populated, this function
423      * will loop through all keys in one hashtable and check that the second
424      * hashtable contains each key and that each key has the same value
425      * associated with it.
426      *
427      * @param hashTable1
428      *        The first hashtable used for testing.
429      * @param hashTable2
430      *        The second hashtable used for testing.
431      * @return boolean
432      *         The result of the two hashtable test.  Returns true if both
433      *         hashtables are determined to be equal, false otherwise.
434      **/
435     public boolean testHashtables(Hashtable hashTable1,
436           Hashtable hashTable2) {
437   if (hashTable1 != null &&
438       hashTable1.size() == 0 &&
439       hashTable2 == null) {
440       return true;
441   } else if (hashTable2 != null &&
442        hashTable2.size() == 0 &&
443        hashTable1 == null) {
444       return true;
445   } else if (hashTable1.size() != hashTable2.size()) {
446       return false;
447   }
448 
449   Enumeration hashTable1Keys = hashTable1.keys();
450   while (hashTable1Keys.hasMoreElements()) {
451       String key = (String)hashTable1Keys.nextElement();
452       if (!hashTable2.containsKey(key)) {
453     return false;
454       } else if (!(hashTable2.get(key)).equals(hashTable2.get(key))) {
455     return false;
456       }         
457   }
458   return true;
459     }
460 
461     /**
462      * This is a conviencce function to test the equality of two vectors.
463      * This function will consider a null vector and an empty vector
464      * equal.  If both the supplied vectors are populated, this function
465      * will loop through all objects held in one vector and check that the
466      * second vector contains each object.
467      *
468      * @param vector1
469      *        The first vector used for testing.
470      * @param vector2
471      *        The second vector used for testing.
472      * @return boolean
473      *         The result of the two vector test.  Returns true if both
474      *         vectors are determined to be equal, false otherwise.
475      **/
476     public boolean testVectors(Vector vector1,
477              Vector vector2) {
478   if (vector1 != null &&
479       vector1.size() == 0 &&
480       vector2 == null) {
481       return true;
482   } else if (vector2 != null &&
483        vector2.size() == 0 &&
484        vector1 == null) {
485       return true;
486   } else if (vector1.size() != vector2.size()) {
487       return false;
488   }
489 
490   Enumeration vector1Elements = vector1.elements();
491   while (vector1Elements.hasMoreElements()) {
492       String element = (String)vector1Elements.nextElement();
493       if (!vector2.contains(element)) {
494     return false;
495       }
496   }
497   return true;
498     }
499 
500     /**
501      * This is a convenience function to split the path information strings
502      * into a token set and then check that each token in the first string
503      * is also in the second string.  Any mismatch will return false.
504      *
505      * @param pathInfoString1
506      *        The first path information string used for testing.
507      * @param pathInfoString2
508      *        The second path information string used for testing.
509      * @param boolean
510      *         The result of the two path information string test.  Returns 
511      *         true if both strings are determined to be equal, false 
512      *         otherwise.
513      **/
514     public boolean testPathInfo(String pathInfoString1,
515         String pathInfoString2) {
516   StringTokenizer pathInfoStringTokens1 = 
517       new StringTokenizer(pathInfoString1, ";", false);
518   StringTokenizer pathInfoStringTokens2 = 
519       new StringTokenizer(pathInfoString2, ";", false);
520 
521   return testStringTokens(pathInfoStringTokens1,
522         pathInfoStringTokens2);
523     }
524 
525     /**
526      * This is a convenience function to split the request URI strings
527      * into a token set and then check that each token in the first string
528      * is also in the second string.  Any mismatch will return false.
529      *
530      * @param uriString1
531      *        The first request URI string used for testing.
532      * @param uriString2
533      *        The second request URI string used for testing.
534      * @param boolean
535      *         The result of the two request URI string test.  Returns 
536      *         true if both strings are determined to be equal, false 
537      *         otherwise.
538      **/
539     public boolean testRequestURI(String uriString1,
540           String uriString2) {
541   StringTokenizer uriStringTokens1 = 
542       new StringTokenizer(uriString1, ";", false);
543   StringTokenizer uriStringTokens2 = 
544       new StringTokenizer(uriString2, ";", false);
545 
546   return testStringTokens(uriStringTokens1,
547         uriStringTokens2);
548     }
549 
550     /**
551      * This is a convenience function to split the query string strings
552      * into a token set and then check that each token in the first string
553      * is also in the second string.  Any mismatch will return false.
554      *
555      * @param queryString1
556      *        The first query string string used for testing.
557      * @param queryString2
558      *        The second query string string used for testing.
559      * @param boolean
560      *         The result of the two query strings string test.  Returns 
561      *         true if both strings are determined to be equal, false 
562      *         otherwise.
563      **/
564     public boolean testQueryString(String queryString1,
565            String queryString2) {
566 
567   StringTokenizer queryStringTokens1 = 
568       new StringTokenizer(queryString1, "%26", false);
569   StringTokenizer queryStringTokens2 = 
570       new StringTokenizer(queryString2, "%26", false);
571 
572   return testStringTokens(queryStringTokens1,
573         queryStringTokens2);
574     }
575 
576     /**
577      * This is a conviencce function to test the equality of two token sets.
578      * If both the supplied token sets are populated, this function
579      * will loop through all objects held in one token set and check that the
580      * second token set contains each object.
581      *
582      * @param tokens1
583      *        The first token set used for testing.
584      * @param tokens2
585      *        The second token set used for testing.
586      * @return boolean
587      *         The result of the two token sets test.  Returns true if both
588      *         token sets are determined to be equal, false otherwise.
589      **/
590     public boolean testStringTokens(StringTokenizer tokens1,
591             StringTokenizer tokens2) {
592   if (tokens1.countTokens() != 
593       tokens2.countTokens()) {
594       return false;
595   }
596   
597   String[] array1 = 
598       new String[tokens1.countTokens()];
599   String[] array2 = 
600       new String[tokens2.countTokens()];
601   int i = 0;
602   int j = 0;
603   while(tokens1.hasMoreTokens()) {
604       array1[i] = tokens1.nextToken();
605       array2[i] = tokens2.nextToken();
606       i++;
607   }
608 
609   for (i = 0; i < array1.length; i++) {
610       for (j = 0; j < array2.length; j++) {
611     if (array1[i].equals(array2[j])) {
612         break;
613     }
614       }
615       if (j == array2.length) {
616     return false;
617       }
618   }
619   return true;
620     }
621 
622     /**
623      * This is a convenience function to format and return valid XML 
624      * representing all the CGI parameters held in this object.  The XML
625      * returned is defined in HttpResponseObject.dtd.
626      *
627      * @return String[]
628      *         An array of CGI parameters in an XML format.
629      **/
630     public String[] getCgiParamStrings() {
631   if (cgiParams == null) {
632       return new String[0];
633   }
634 
635   String[] cgiParamStrings = new String[cgiParams.size()];
636 
637   Enumeration keys = cgiParams.keys();
638   int i = 0;
639   while (keys.hasMoreElements()) {
640       String currentKey = (String)keys.nextElement();
641       cgiParamStrings[i++] = 
642     BEGIN_ELEMENT_TAG +
643     CGI_PARAM_ELEMENT + " " +
644     CGI_PARAM_NAME_ATTR + "=\"" + currentKey + "\" " +
645     CGI_PARAM_VALUE_ATTR + "=\"" + 
646     cgiParams.get(currentKey) + "\"" +
647     END_EMPTY_ELEMENT_TAG;
648   }
649   return cgiParamStrings;
650     }
651 
652     /**
653      * This is a convenience function to format and return valid XML 
654      * representing all the CGI arguments held in this object.  The XML
655      * returned is defined in HttpResponseObject.dtd.
656      *
657      * @return String[]
658      *         An array of CGI arguments in an XML format.
659      **/
660     public String[] getCgiArgStrings() {
661   if (cgiArgs == null) {
662       return new String[0];
663   }
664 
665   String[] cgiArgStrings = new String[cgiArgs.size()];
666 
667   Enumeration keys = cgiArgs.keys();
668   int i = 0;
669   while (keys.hasMoreElements()) {
670       String currentKey = (String)keys.nextElement();
671       cgiArgStrings[i++] = 
672     BEGIN_ELEMENT_TAG +
673     CGI_ARG_ELEMENT + " " +
674     CGI_ARG_NAME_ATTR + "=\"" + currentKey + "\" " +
675     CGI_ARG_VALUE_ATTR + "=\"" + 
676     cgiArgs.get(currentKey) + "\"" +
677     END_EMPTY_ELEMENT_TAG;
678   }
679   return cgiArgStrings;
680     }
681 
682     /**
683      * This is a convenience function to format and return valid XML 
684      * representing all the headers held in this object.  The XML
685      * returned is defined in HttpResponseObject.dtd.
686      *
687      * @return String[]
688      *         An array of headers in an XML format.
689      **/
690     public String[] getHeaderStrings() {
691   if (headers == null) {
692       return new String[0];
693   }
694 
695   String[] headerStrings = new String[headers.size()];
696 
697   Enumeration keys = headers.keys();
698   int i = 0;
699   while (keys.hasMoreElements()) {
700       String currentKey = (String)keys.nextElement();
701       headerStrings[i++] = 
702     BEGIN_ELEMENT_TAG +
703     HEADER_ELEMENT + " " +
704     HEADER_NAME_ATTR + "=\"" + currentKey + "\" " +
705     HEADER_VALUE_ATTR + "=\"" + 
706     headers.get(currentKey) + "\"" +
707     END_EMPTY_ELEMENT_TAG;
708   }
709   return headerStrings;
710     }
711       
712     /**
713      * This is a convenience function to format and return valid XML 
714      * representing all the cookies held in this object.  The XML
715      * returned is defined in HttpResponseObject.dtd.
716      *
717      * @return String[]
718      *         An array of cookies in an XML format.
719      **/
720     public String[] getCookieStrings() {
721   if (cookies == null) {
722       return new String[0];
723   }
724 
725   String[] cookieStrings = new String[cookies.size()];
726 
727   Enumeration keys = cookies.keys();
728   int i = 0;
729   while (keys.hasMoreElements()) {
730       String currentKey = (String)keys.nextElement();
731       cookieStrings[i++] = 
732     BEGIN_ELEMENT_TAG +
733     COOKIE_ELEMENT + " " +
734     COOKIE_NAME_ATTR + "=\"" + currentKey + "\" " +
735     COOKIE_VALUE_ATTR + "=\"" + 
736     cookies.get(currentKey) + "\"" +
737     END_EMPTY_ELEMENT_TAG;
738   }
739   return cookieStrings;
740     }
741 
742     /**
743      * This is a convenience function to format and return valid XML 
744      * representing all the file uploads held in this object.  The XML
745      * returned is defined in HttpResponseObject.dtd.
746      *
747      * @return String[]
748      *         An array of file uploads in an XML format.
749      **/
750     public String[] getFileUploadStrings() {
751   if (md5HashKey == null) {
752       return new String[0];
753   }
754 
755   String[] md5Strings = new String[md5HashKey.size()];
756 
757   Enumeration elements = md5HashKey.elements();
758   int i = 0;
759   while (elements.hasMoreElements()) {
760       String currentElement = (String)elements.nextElement();
761       md5Strings[i++] = 
762     BEGIN_ELEMENT_TAG +
763     FILE_UPLOAD_ELEMENT + " " +
764     FILE_UPLOAD_MD5_HASH_KEY_ATTR + "=\"" + 
765     currentElement + "\"" +
766     END_EMPTY_ELEMENT_TAG;
767   }
768   return md5Strings;
769     }
770   
771     /**
772      * This is a convenience function to format and return valid XML 
773      * representing the HttpRequestInfo element and all its attributes.
774      * The XML returned is defined in HttpResponseObject.dtd.  Position
775      * zero in the returned array represents the start tag for this
776      * element.  Position one in the returned array represents the stop
777      * tag for this element.
778      *
779      * @return String[]
780      *         An array on length two holding the start and stop tags for
781      *         this element and all its attributes.
782      **/
783     public String[] getHttpRequestInfoStrings() {
784   String[] httpRequestInfoStrings = new String[2];
785   
786   StringBuffer requestBuffer = new StringBuffer();
787   requestBuffer.append(BEGIN_ELEMENT_TAG +
788            HTTP_REQUEST_INFO_ELEMENT + " ");
789   requestBuffer.append(HTTP_REQUEST_INFO_AUTH_TYPE_ATTR + "=\"" +
790            authType + "\" ");
791   requestBuffer.append(HTTP_REQUEST_INFO_METHOD_ATTR + "=\"" +
792            method + "\" ");
793   requestBuffer.append(HTTP_REQUEST_INFO_PATH_INFO_ATTR + "=\"" +
794            pathInfo + "\" ");
795   requestBuffer.append(HTTP_REQUEST_INFO_PATH_TRANSLATED_ATTR + "=\"" +
796            pathTranslated + "\" ");
797   requestBuffer.append(HTTP_REQUEST_INFO_QUERY_STRING_ATTR + "=\"" +
798            queryString + "\" ");
799   requestBuffer.append(HTTP_REQUEST_INFO_REMOTE_USER_ATTR + "=\"" +
800            remoteUser + "\" ");
801   requestBuffer.append(HTTP_REQUEST_INFO_REQUEST_URI_ATTR + "=\"" +
802            requestURI + "\" ");
803   requestBuffer.append(HTTP_REQUEST_INFO_SERVLET_PATH_ATTR + "=\"" +
804            servletPath + "\" ");
805   requestBuffer.append(HTTP_REQUEST_INFO_SESSION_ATTR + "=\"" +
806            session + "\" ");
807   requestBuffer.append(HTTP_REQUEST_INFO_SESSION_ID_FROM_COOKIE_ATTR + 
808            "=\"" + sessionIdFromCookie + "\" ");
809   requestBuffer.append(HTTP_REQUEST_INFO_SESSION_ID_FROM_URL_ATTR + 
810            "=\"" + sessionIdFromURL + "\" ");
811   requestBuffer.append(HTTP_REQUEST_INFO_SESSION_ID_INVALID_ATTR + 
812            "=\"" + sessionIdInvalid + "\"");
813   requestBuffer.append(END_PCDATA_ELEMENT_TAG);
814 
815   httpRequestInfoStrings[0] = requestBuffer.toString();
816   httpRequestInfoStrings[1] = END_ELEMENT_TAG + 
817       HTTP_REQUEST_INFO_ELEMENT + END_PCDATA_ELEMENT_TAG;
818 
819   return httpRequestInfoStrings;
820     }
821 
822     /**
823      * This is a convenience function to format and return valid XML 
824      * representing the HttpResponseObject element and all its attributes.
825      * The XML returned is defined in HttpResponseObject.dtd.  Position
826      * zero in the returned array represents the start tag for this
827      * element.  Position one in the returned array represents the stop
828      * tag for this element.
829      *
830      * @return String[]
831      *         An array on length two holding the start and stop tags for
832      *         this element and all its attributes.
833      **/
834     public String[] getHttpResponseObjectStrings() {
835   String[] httpResponseObjectStrings = new String[2];
836   
837   httpResponseObjectStrings[0] = BEGIN_ELEMENT_TAG +
838       HTTP_RESPONSE_OBJ_ELEMENT + END_PCDATA_ELEMENT_TAG;
839   httpResponseObjectStrings[1] = END_ELEMENT_TAG + 
840       HTTP_RESPONSE_OBJ_ELEMENT + END_PCDATA_ELEMENT_TAG;
841   return httpResponseObjectStrings;
842     }
843 }
844