KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > http > HttpFields


1 // ========================================================================
2
// $Id: HttpFields.java,v 1.76 2005/08/13 00:01:24 gregwilkins Exp $
3
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15

16 package org.mortbay.http;
17
18 import java.io.IOException JavaDoc;
19 import java.io.StringWriter JavaDoc;
20 import java.io.Writer JavaDoc;
21 import java.text.SimpleDateFormat JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Calendar JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.Date JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.GregorianCalendar JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Locale JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.NoSuchElementException JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36 import java.util.TimeZone JavaDoc;
37
38 import javax.servlet.http.Cookie JavaDoc;
39
40 import org.apache.commons.logging.Log;
41 import org.mortbay.log.LogFactory;
42 import org.mortbay.util.DateCache;
43 import org.mortbay.util.LazyList;
44 import org.mortbay.util.LineInput;
45 import org.mortbay.util.LogSupport;
46 import org.mortbay.util.QuotedStringTokenizer;
47 import org.mortbay.util.StringMap;
48 import org.mortbay.util.StringUtil;
49 import org.mortbay.util.URI;
50
51 /* ------------------------------------------------------------ */
52 /** HTTP Fields.
53  * A collection of HTTP header and or Trailer fields.
54  * This class is not synchronized and needs to be protected from
55  * concurrent access.
56  *
57  * This class is not synchronized as it is expected that modifications
58  * will only be performed by a single thread.
59  *
60  * @version $Id: HttpFields.java,v 1.76 2005/08/13 00:01:24 gregwilkins Exp $
61  * @author Greg Wilkins (gregw)
62  */

63 public class HttpFields
64 {
65     private static Log log = LogFactory.getLog(HttpFields.class);
66         
67     /* ------------------------------------------------------------ */
68     /** General Fields.
69      */

70     public final static String JavaDoc
71         __CacheControl = "Cache-Control",
72         __Connection = "Connection",
73         __Date = "Date",
74         __Pragma = "Pragma",
75         __ProxyConnection = "Proxy-Connection",
76         __Trailer = "Trailer",
77         __TransferEncoding = "Transfer-Encoding",
78         __Upgrade = "Upgrade",
79         __Via = "Via",
80         __Warning = "Warning";
81         
82     /* ------------------------------------------------------------ */
83     /** Entity Fields.
84      */

85     public final static String JavaDoc
86         __Allow = "Allow",
87         __ContentEncoding = "Content-Encoding",
88         __ContentLanguage = "Content-Language",
89         __ContentLength = "Content-Length",
90         __ContentLocation = "Content-Location",
91         __ContentMD5 = "Content-MD5",
92         __ContentRange = "Content-Range",
93         __ContentType = "Content-Type",
94         __Expires = "Expires",
95         __LastModified = "Last-Modified";
96     
97     /* ------------------------------------------------------------ */
98     /** Request Fields.
99      */

100     public final static String JavaDoc
101         __Accept = "Accept",
102         __AcceptCharset = "Accept-Charset",
103         __AcceptEncoding = "Accept-Encoding",
104         __AcceptLanguage = "Accept-Language",
105         __Authorization = "Authorization",
106         __Expect = "Expect",
107         __Forwarded = "Forwarded",
108         __From = "From",
109         __Host = "Host",
110         __IfMatch = "If-Match",
111         __IfModifiedSince = "If-Modified-Since",
112         __IfNoneMatch = "If-None-Match",
113         __IfRange = "If-Range",
114         __IfUnmodifiedSince = "If-Unmodified-Since",
115         __KeepAlive = "keep-alive",
116         __MaxForwards = "Max-Forwards",
117         __ProxyAuthorization = "Proxy-Authorization",
118         __Range = "Range",
119         __RequestRange = "Request-Range",
120         __Referer = "Referer",
121         __TE = "TE",
122         __UserAgent = "User-Agent",
123         __XForwardedFor = "X-Forwarded-For";
124     
125
126     /* ------------------------------------------------------------ */
127     /** Response Fields.
128      */

129     public final static String JavaDoc
130         __AcceptRanges = "Accept-Ranges",
131         __Age = "Age",
132         __ETag = "ETag",
133         __Location = "Location",
134         __ProxyAuthenticate = "Proxy-Authenticate",
135         __RetryAfter = "Retry-After",
136         __Server = "Server",
137         __ServletEngine = "Servlet-Engine",
138         __Vary = "Vary",
139         __WwwAuthenticate = "WWW-Authenticate";
140      
141     /* ------------------------------------------------------------ */
142     /** Other Fields.
143      */

144     public final static String JavaDoc
145         __Cookie = "Cookie",
146         __SetCookie = "Set-Cookie",
147         __SetCookie2 = "Set-Cookie2",
148         __MimeVersion ="MIME-Version",
149         __Identity ="identity",
150         __SoapAction ="SOAPAction";
151
152     /* ------------------------------------------------------------ */
153     /** Private class to hold Field name info
154      */

155     private static final class FieldInfo
156     {
157         String JavaDoc _name;
158         String JavaDoc _lname;
159         boolean _inlineValues;
160         int _hashCode;
161         static int __hashCode;
162         
163         FieldInfo(String JavaDoc name, boolean inline)
164         {
165             synchronized(FieldInfo.class)
166             {
167                 _name=name;
168                 _lname=StringUtil.asciiToLowerCase(name);
169                 _inlineValues=inline;
170                 
171                 _hashCode=__hashCode++;
172                 
173                 if (__hashCode < __maxCacheSize)
174                 {
175                     FieldInfo oldInfo = (FieldInfo)__info.get(name);
176                     if (oldInfo == null)
177                     {
178                         __info.put(name, this);
179                         if (!name.equals(_lname))
180                             __info.put(_lname, this);
181                     }
182                     else
183                         _hashCode = oldInfo._hashCode;
184                 }
185             }
186         }
187
188         public String JavaDoc toString()
189         {
190             return "["+_name+","+_hashCode+","+_inlineValues+"]";
191         }
192
193         public int hashCode()
194         {
195             return _hashCode;
196         }
197
198         public boolean equals(Object JavaDoc o)
199         {
200             if (o==null || !(o instanceof FieldInfo))
201                 return false;
202             FieldInfo fi = (FieldInfo)o;
203             return
204                 fi==this ||
205                 fi._hashCode==_hashCode ||
206                 fi._name.equals(_name);
207         }
208     }
209
210     /* ------------------------------------------------------------ */
211     private static final StringMap __info = new StringMap(true);
212     private static final StringMap __values = new StringMap(true);
213     private static final int __maxCacheSize=128;
214     
215     /* ------------------------------------------------------------ */
216     static
217     {
218         // Initialize FieldInfo's with special values.
219
// In order of most frequently used.
220
new FieldInfo(__Host,false);
221         
222         new FieldInfo(__KeepAlive,false);
223         new FieldInfo(__Connection,false);
224         
225         new FieldInfo(__Cookie,false);
226         
227         new FieldInfo(__Accept,false);
228         new FieldInfo(__AcceptLanguage,false);
229         new FieldInfo(__AcceptEncoding,false);
230         new FieldInfo(__AcceptCharset,false);
231         new FieldInfo(__CacheControl,false);
232         new FieldInfo(__SetCookie,false);
233         new FieldInfo(__SetCookie2,false);
234         
235         new FieldInfo(__Date,false);
236         new FieldInfo(__TransferEncoding,true);
237         new FieldInfo(__ContentEncoding,true);
238         new FieldInfo(__ContentLength,false);
239         new FieldInfo(__Expires,false);
240         new FieldInfo(__Expect,false);
241         
242         new FieldInfo(__Referer,false);
243         new FieldInfo(__TE,false);
244         new FieldInfo(__UserAgent,false);
245         
246         new FieldInfo(__IfModifiedSince,false);
247         new FieldInfo(__IfRange,false);
248         new FieldInfo(__IfUnmodifiedSince,false);
249
250         new FieldInfo(__Location,false);
251         new FieldInfo(__Server,false);
252         new FieldInfo(__ServletEngine,false);
253         
254         new FieldInfo(__AcceptRanges,false);
255         new FieldInfo(__Range,false);
256         new FieldInfo(__RequestRange,false);
257
258         new FieldInfo(__SoapAction,false);
259         
260         new FieldInfo(__ContentLocation,false);
261         new FieldInfo(__ContentMD5,false);
262         new FieldInfo(__ContentRange,false);
263         new FieldInfo(__ContentType,false);
264         new FieldInfo(__LastModified,false);
265         new FieldInfo(__Authorization,false);
266         new FieldInfo(__From,false);
267         new FieldInfo(__MaxForwards,false);
268         new FieldInfo(__ProxyAuthenticate,false);
269         new FieldInfo(__Age,false);
270         new FieldInfo(__ETag,false);
271         new FieldInfo(__RetryAfter,false);
272
273         
274     }
275     
276     /* ------------------------------------------------------------ */
277     private static FieldInfo getFieldInfo(String JavaDoc name)
278     {
279         FieldInfo info = (FieldInfo)__info.get(name);
280         if (info==null)
281             info = new FieldInfo(name,false);
282         return info;
283     }
284     
285     /* ------------------------------------------------------------ */
286     private static FieldInfo getFieldInfo(char[] name,int offset,int length)
287     {
288         Map.Entry JavaDoc entry = __info.getEntry(name,offset,length);
289         if (entry==null)
290             return new FieldInfo(new String JavaDoc(name,offset,length),false);
291
292         return (FieldInfo) entry.getValue();
293     }
294     
295     /* ------------------------------------------------------------ */
296     /** Fields Values.
297      */

298     public final static String JavaDoc __Chunked = "chunked";
299     public final static String JavaDoc __Close = "close";
300     public final static String JavaDoc __TextHtml = "text/html";
301     public final static String JavaDoc __MessageHttp = "message/http";
302     public final static String JavaDoc __WwwFormUrlEncode =
303         "application/x-www-form-urlencoded";
304     public static final String JavaDoc __ExpectContinue="100-continue";
305
306     static
307     {
308         __values.put(__KeepAlive,__KeepAlive);
309         __values.put(__Chunked,__Chunked);
310         __values.put(__Close,__Close);
311         __values.put(__TextHtml,__TextHtml);
312         __values.put(__MessageHttp,__MessageHttp);
313         __values.put(__WwwFormUrlEncode,__WwwFormUrlEncode);
314         __values.put(__ExpectContinue,__ExpectContinue);
315         __values.put("max-age=0","max-age=0");
316         __values.put("no-cache","no-cache");
317         __values.put("300","300");
318         __values.put("ISO-8859-1, utf-8;q=0.66, *;q=0.66","ISO-8859-1, utf-8;q=0.66, *;q=0.66");
319     }
320     
321     /* ------------------------------------------------------------ */
322     public final static String JavaDoc __separators = ", \t";
323
324     /* ------------------------------------------------------------ */
325     public final static char[] __CRLF = {'\015','\012'};
326     public final static char[] __COLON = {':',' '};
327
328     /* ------------------------------------------------------------ */
329     private static String JavaDoc[] DAYS= { "Sat","Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
330     private static String JavaDoc[] MONTHS= { "Jan","Feb","Mar","Apr","May","Jun",
331                                       "Jul","Aug","Sep","Oct","Nov","Dec","Jan" };
332
333
334     /* ------------------------------------------------------------ */
335     /** Format HTTP date
336      * "EEE, dd MMM yyyy HH:mm:ss 'GMT'" or
337      * "EEE, dd-MMM-yy HH:mm:ss 'GMT'"for cookies
338      */

339     public static String JavaDoc formatDate(long date, boolean cookie)
340     {
341         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(32);
342         HttpCal gc = new HttpCal();
343         gc.setTimeInMillis(date);
344         formatDate(buf,gc,cookie);
345         return buf.toString();
346     }
347
348     /* ------------------------------------------------------------ */
349     /** Format HTTP date
350      * "EEE, dd MMM yyyy HH:mm:ss 'GMT'" or
351      * "EEE, dd-MMM-yy HH:mm:ss 'GMT'"for cookies
352      */

353     public static String JavaDoc formatDate(Calendar JavaDoc calendar, boolean cookie)
354     {
355         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(32);
356         formatDate(buf,calendar,cookie);
357         return buf.toString();
358     }
359
360     /* ------------------------------------------------------------ */
361     /** Format HTTP date
362      * "EEE, dd MMM yyyy HH:mm:ss 'GMT'" or
363      * "EEE, dd-MMM-yy HH:mm:ss 'GMT'"for cookies
364      */

365     public static String JavaDoc formatDate(StringBuffer JavaDoc buf, long date, boolean cookie)
366     {
367         HttpCal gc = new HttpCal();
368         gc.setTimeInMillis(date);
369         formatDate(buf,gc,cookie);
370         return buf.toString();
371     }
372
373     /* ------------------------------------------------------------ */
374     /** Format HTTP date
375      * "EEE, dd MMM yyyy HH:mm:ss 'GMT'" or
376      * "EEE, dd-MMM-yy HH:mm:ss 'GMT'"for cookies
377      */

378     public static void formatDate(StringBuffer JavaDoc buf,Calendar JavaDoc calendar, boolean cookie)
379     {
380         // "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
381
// "EEE, dd-MMM-yy HH:mm:ss 'GMT'", cookie
382

383         int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
384         int day_of_month = calendar.get(Calendar.DAY_OF_MONTH);
385         int month = calendar.get(Calendar.MONTH);
386         int year = calendar.get(Calendar.YEAR);
387         int century = year/100;
388         year=year%100;
389
390         long tm = (calendar instanceof HttpCal)?(((HttpCal)calendar).getTimeInMillis()):calendar.getTime().getTime();
391         int epoch=(int)((tm/1000) % (60*60*24));
392         int seconds=epoch%60;
393         epoch=epoch/60;
394         int minutes=epoch%60;
395         int hours=epoch/60;
396         
397         buf.append(DAYS[day_of_week]);
398         buf.append(',');
399         buf.append(' ');
400         StringUtil.append2digits(buf,day_of_month);
401         
402         if (cookie)
403         {
404             buf.append('-');
405             buf.append(MONTHS[month]);
406             buf.append('-');
407             StringUtil.append2digits(buf,year);
408         }
409         else
410         {
411             buf.append(' ');
412             buf.append(MONTHS[month]);
413             buf.append(' ');
414             StringUtil.append2digits(buf,century);
415             StringUtil.append2digits(buf,year);
416         }
417         buf.append(' ');
418         StringUtil.append2digits(buf,hours);
419         buf.append(':');
420         StringUtil.append2digits(buf,minutes);
421         buf.append(':');
422         StringUtil.append2digits(buf,seconds);
423         buf.append(" GMT");
424     }
425
426     /* -------------------------------------------------------------- */
427     private static TimeZone JavaDoc __GMT = TimeZone.getTimeZone("GMT");
428     public final static DateCache __dateCache =
429         new DateCache("EEE, dd MMM yyyy HH:mm:ss 'GMT'",
430                       Locale.US);
431     
432     /* ------------------------------------------------------------ */
433     private final static String JavaDoc __dateReceiveFmt[] =
434     {
435         "EEE, dd MMM yyyy HH:mm:ss zzz",
436         "EEE, dd-MMM-yy HH:mm:ss zzz",
437         "EEE MMM dd HH:mm:ss yyyy",
438         "EEE, dd MMM yyyy HH:mm:ss zzz",
439         "EEE, dd-MMM-yy HH:mm:ss zzz",
440         "dd MMM yyyy HH:mm:ss",
441         "dd-MMM-yy HH:mm:ss",
442     };
443     public static SimpleDateFormat JavaDoc __dateReceiveSource[];
444     public static final ThreadLocal JavaDoc __dateReceiveCache=new ThreadLocal JavaDoc();
445     static
446     {
447         __GMT.setID("GMT");
448         __dateCache.setTimeZone(__GMT);
449         __dateReceiveSource = new SimpleDateFormat JavaDoc[__dateReceiveFmt.length];
450         for(int i=0;i<__dateReceiveSource.length;i++)
451         {
452             __dateReceiveSource[i] =
453                 new SimpleDateFormat JavaDoc(__dateReceiveFmt[i],Locale.US);
454             __dateReceiveSource[i].setTimeZone(__GMT);
455         }
456     }
457     
458     public final static String JavaDoc __01Jan1970=HttpFields.formatDate(0,false);
459
460
461     /* ------------------------------------------------------------ */
462     /* ------------------------------------------------------------ */
463     /* ------------------------------------------------------------ */
464     private static final class Field
465     {
466         FieldInfo _info;
467         String JavaDoc _value;
468         Field _next;
469         Field _prev;
470         int _version;
471
472         /* ------------------------------------------------------------ */
473         Field(FieldInfo info, String JavaDoc value, int version)
474         {
475             _info=info;
476             _value=value;
477             _next=null;
478             _prev=null;
479             _version=version;
480         }
481         
482         /* ------------------------------------------------------------ */
483         Field(FieldInfo info, char[] buf, int offset, int length, int version)
484         {
485             Map.Entry JavaDoc valueEntry=__values.getEntry(buf,offset,length);
486             String JavaDoc value=null;
487             if (valueEntry!=null)
488                 value=(String JavaDoc)valueEntry.getKey();
489             else
490                 value=new String JavaDoc(buf,offset,length);
491             
492             _info=info;
493             _value=value;
494             _next=null;
495             _prev=null;
496             _version=version;
497         }
498         
499         /* ------------------------------------------------------------ */
500         public boolean equals(Object JavaDoc o)
501         {
502             return (o instanceof Field) &&
503                 o==this &&
504                 _version==((Field)o)._version;
505         }
506
507         /* ------------------------------------------------------------ */
508         public int hashCode()
509         {
510             return _info.hashCode()*_version;
511         }
512         
513         /* ------------------------------------------------------------ */
514         void clear()
515         {
516             _version=-1;
517         }
518         
519         /* ------------------------------------------------------------ */
520         void destroy()
521         {
522             _info=null;
523             _value=null;
524             _next=null;
525             _prev=null;
526             _version=-1;
527         }
528         
529         /* ------------------------------------------------------------ */
530         void reset(String JavaDoc value,int version)
531         {
532             _value=value;
533             _version=version;
534         }
535         
536         /* ------------------------------------------------------------ */
537         /** Reassign a value to this field.
538          * Checks if the value is the same as that in the char array, if so
539          * then just reuse existing value.
540          */

541         void reset(char[] buf, int offset, int length, int version)
542         {
543             _version=version;
544             if (!StringUtil.equals(_value,buf,offset,length))
545             {
546                 Map.Entry JavaDoc valueEntry=__values.getEntry(buf,offset,length);
547                 String JavaDoc value=null;
548                 if (valueEntry!=null)
549                     value=(String JavaDoc)valueEntry.getKey();
550                 else
551                     value=new String JavaDoc(buf,offset,length);
552                 _value=value;
553             }
554         }
555
556         
557         /* ------------------------------------------------------------ */
558         void write(Writer JavaDoc writer, int version)
559             throws IOException JavaDoc
560         {
561             if (_info==null || _version!=version)
562                 return;
563             if (_info._inlineValues)
564             {
565                 if (_prev!=null)
566                     return;
567                 writer.write(_info._name);
568                 writer.write(__COLON);
569                 Field f=this;
570                 while (true)
571                 {
572                     writer.write(QuotedStringTokenizer.quote(f._value,", \t"));
573                     f=f._next;
574                     if (f==null)
575                         break;
576                     writer.write(",");
577                 }
578                 writer.write(__CRLF);
579             }
580             else
581             {
582                 writer.write(_info._name);
583                 writer.write(__COLON);
584                 writer.write(_value);
585                 writer.write(__CRLF);
586             }
587         }
588
589         /* ------------------------------------------------------------ */
590         String JavaDoc getDisplayName()
591         {
592             return _info._name;
593         }
594         
595         /* ------------------------------------------------------------ */
596         public String JavaDoc toString()
597         {
598             return ("["+
599                 (_prev==null?"":"<-")+
600                 getDisplayName()+"="+_value+
601                 (_next==null?"":"->")+
602                 "]");
603         }
604     }
605     
606     /* ------------------------------------------------------------ */
607     private static Float JavaDoc __one = new Float JavaDoc("1.0");
608     private static Float JavaDoc __zero = new Float JavaDoc("0.0");
609     private static StringMap __qualities=new StringMap();
610     static
611     {
612         __qualities.put(null,__one);
613         __qualities.put("1.0",__one);
614         __qualities.put("1",__one);
615         __qualities.put("0.9",new Float JavaDoc("0.9"));
616         __qualities.put("0.8",new Float JavaDoc("0.8"));
617         __qualities.put("0.7",new Float JavaDoc("0.7"));
618         __qualities.put("0.66",new Float JavaDoc("0.66"));
619         __qualities.put("0.6",new Float JavaDoc("0.6"));
620         __qualities.put("0.5",new Float JavaDoc("0.5"));
621         __qualities.put("0.4",new Float JavaDoc("0.4"));
622         __qualities.put("0.33",new Float JavaDoc("0.33"));
623         __qualities.put("0.3",new Float JavaDoc("0.3"));
624         __qualities.put("0.2",new Float JavaDoc("0.2"));
625         __qualities.put("0.1",new Float JavaDoc("0.1"));
626         __qualities.put("0",__zero);
627         __qualities.put("0.0",__zero);
628     }
629     
630     
631     /* -------------------------------------------------------------- */
632     private ArrayList JavaDoc _fields=new ArrayList JavaDoc(15);
633     private int[] _index=new int[__maxCacheSize];
634     private int _version;
635     private SimpleDateFormat JavaDoc _dateReceive[];
636     private StringBuffer JavaDoc _dateBuffer;
637     private HttpCal _calendar;
638
639     /* ------------------------------------------------------------ */
640     /** Constructor.
641      */

642     public HttpFields()
643     {
644         Arrays.fill(_index,-1);
645     }
646
647     
648     /* ------------------------------------------------------------ */
649     public int size()
650     {
651         return _fields.size();
652     }
653     
654     /* -------------------------------------------------------------- */
655     /** Get enumeration of header _names.
656      * Returns an enumeration of strings representing the header _names
657      * for this request.
658      */

659     public Enumeration JavaDoc getFieldNames()
660     {
661         return new Enumeration JavaDoc()
662             {
663                 int i=0;
664                 Field field=null;
665
666                 public boolean hasMoreElements()
667                 {
668                     if (field!=null)
669                         return true;
670                     while (i<_fields.size())
671                     {
672                         Field f=(Field)_fields.get(i++);
673                         if (f!=null && f._version==_version && f._prev==null)
674                         {
675                             field=f;
676                             return true;
677                         }
678                     }
679                     return false;
680                 }
681
682                 public Object JavaDoc nextElement()
683                     throws NoSuchElementException JavaDoc
684                 {
685                     if (field!=null || hasMoreElements())
686                     {
687                         String JavaDoc n=field._info._name;
688                         field=null;
689                         return n;
690                     }
691                     throw new NoSuchElementException JavaDoc();
692                 }
693             };
694     }
695     
696     /* ------------------------------------------------------------ */
697     Field getField(String JavaDoc name)
698     {
699         FieldInfo info=getFieldInfo(name);
700         return getField(info,true);
701     }
702         
703     /* ------------------------------------------------------------ */
704     Field getField(FieldInfo info, boolean getValid)
705     {
706         int hi=info.hashCode();
707         
708         if (hi<_index.length)
709         {
710             if (_index[hi]>=0)
711             {
712                 Field field=(Field)(_fields.get(_index[hi]));
713                 
714                 return (field!=null && (!getValid||field._version==_version))?field:null;
715             }
716         }
717         else
718         {
719             for (int i=0;i<_fields.size();i++)
720             {
721                 Field field=(Field)_fields.get(i);
722                 if (info.equals(field._info) && (!getValid||field._version==_version))
723                     return field;
724             }
725         }
726         return null;
727     }
728     
729     /* ------------------------------------------------------------ */
730     public boolean containsKey(String JavaDoc name)
731     {
732         FieldInfo info=getFieldInfo(name);
733         return getField(info,true)!=null;
734     }
735     
736     /* -------------------------------------------------------------- */
737     /**
738      * @return the value of a field, or null if not found. For
739      * multiple fields of the same name, only the first is returned.
740      * @param name the case-insensitive field name
741      */

742     public String JavaDoc get(String JavaDoc name)
743     {
744         FieldInfo info=getFieldInfo(name);
745         Field field=getField(info,true);
746         if (field!=null)
747             return field._value;
748         return null;
749     }
750     
751     /* -------------------------------------------------------------- */
752     /** Get multi headers
753      * @return Enumeration of the values, or null if no such header.
754      * @param name the case-insensitive field name
755      */

756     public Enumeration JavaDoc getValues(String JavaDoc name)
757     {
758         FieldInfo info=getFieldInfo(name);
759         final Field field=getField(info,true);
760
761         if (field!=null)
762         {
763             return new Enumeration JavaDoc()
764                 {
765                     Field f=field;
766                     
767                     public boolean hasMoreElements()
768                     {
769                         while (f!=null && f._version!=_version)
770                             f=f._next;
771                         return f!=null;
772                     }
773                         
774                     public Object JavaDoc nextElement()
775                         throws NoSuchElementException JavaDoc
776                     {
777                         if (f==null)
778                             throw new NoSuchElementException JavaDoc();
779                         Field n=f;
780                         do f=f._next; while (f!=null && f._version!=_version);
781                         return n._value;
782                     }
783                 };
784         }
785         return null;
786     }
787     
788     /* -------------------------------------------------------------- */
789     /** Get multi field values with separator.
790      * The multiple values can be represented as separate headers of
791      * the same name, or by a single header using the separator(s), or
792      * a combination of both. Separators may be quoted.
793      * @param name the case-insensitive field name
794      * @param separators String of separators.
795      * @return Enumeration of the values, or null if no such header.
796      */

797     public Enumeration JavaDoc getValues(String JavaDoc name,final String JavaDoc separators)
798     {
799         final Enumeration JavaDoc e = getValues(name);
800         if (e==null)
801             return null;
802         return new Enumeration JavaDoc()
803             {
804                 QuotedStringTokenizer tok=null;
805                 public boolean hasMoreElements()
806                 {
807                     if (tok!=null && tok.hasMoreElements())
808                             return true;
809                     while (e.hasMoreElements())
810                     {
811                         String JavaDoc value=(String JavaDoc)e.nextElement();
812                         tok=new QuotedStringTokenizer(value,separators,false,false);
813                         if (tok.hasMoreElements())
814                             return true;
815                     }
816                     tok=null;
817                     return false;
818                 }
819                         
820                 public Object JavaDoc nextElement()
821                     throws NoSuchElementException JavaDoc
822                 {
823                     if (!hasMoreElements())
824                         throw new NoSuchElementException JavaDoc();
825                     String JavaDoc next=(String JavaDoc) tok.nextElement();
826             if (next!=null)next=next.trim();
827             return next;
828                 }
829             };
830     }
831     
832     /* -------------------------------------------------------------- */
833     /** Set a field.
834      * @param name the name of the field
835      * @param value the value of the field. If null the field is cleared.
836      */

837     public String JavaDoc put(String JavaDoc name,String JavaDoc value)
838     {
839         if (value==null)
840             return remove(name);
841         
842         FieldInfo info=getFieldInfo(name);
843         Field field=getField(info,false);
844         // Look for value to replace.
845
if (field!=null)
846         {
847             String JavaDoc old=(field._version==_version)?field._value:null;
848             field.reset(value,_version);
849
850             field=field._next;
851             while(field!=null)
852             {
853                 field.clear();
854                 field=field._next;
855             }
856             return old;
857         }
858         else
859         {
860             // new value;
861
field=new Field(info,value,_version);
862             int hi=info.hashCode();
863             if (hi<_index.length)
864                 _index[hi]=_fields.size();
865             _fields.add(field);
866             return null;
867         }
868     }
869     
870         
871     /* -------------------------------------------------------------- */
872     /** Set a field.
873      * @param name the name of the field
874      * @param list the List value of the field. If null the field is cleared.
875      */

876     public void put(String JavaDoc name,List JavaDoc list)
877     {
878         if (list==null || list.size()==0)
879         {
880             remove(name);
881             return;
882         }
883         
884         Object JavaDoc v=list.get(0);
885         if (v!=null)
886             put(name,v.toString());
887         else
888             remove(name);
889         
890         if (list.size()>1)
891         {
892             java.util.Iterator JavaDoc iter = list.iterator();
893             iter.next();
894             while(iter.hasNext())
895             {
896                 v=iter.next();
897                 if (v!=null)
898                     add(name,v.toString());
899             }
900         }
901     }
902
903     
904     /* -------------------------------------------------------------- */
905     /** Add to or set a field.
906      * If the field is allowed to have multiple values, add will add
907      * multiple headers of the same name.
908      * @param name the name of the field
909      * @param value the value of the field.
910      * @exception IllegalArgumentException If the name is a single
911      * valued field and already has a value.
912      */

913     public void add(String JavaDoc name,String JavaDoc value)
914         throws IllegalArgumentException JavaDoc
915     {
916         if (value==null)
917             throw new IllegalArgumentException JavaDoc("null value");
918         
919         FieldInfo info=getFieldInfo(name);
920         Field field=getField(info,false);
921         Field last=null;
922         if (field!=null)
923         {
924             while(field!=null && field._version==_version)
925             {
926                 last=field;
927                 field=field._next;
928             }
929         }
930
931         if (field!=null)
932             field.reset(value,_version);
933         else
934         {
935             // create the field
936
field=new Field(info,value,_version);
937             
938             // look for chain to add too
939
if(last!=null)
940             {
941                 field._prev=last;
942                 last._next=field;
943             }
944             else if (info.hashCode()<_index.length)
945                 _index[info.hashCode()]=_fields.size();
946             
947             _fields.add(field);
948         }
949     }
950     
951     /* ------------------------------------------------------------ */
952     /** Remove a field.
953      * @param name
954      */

955     public String JavaDoc remove(String JavaDoc name)
956     {
957         String JavaDoc old=null;
958         FieldInfo info=getFieldInfo(name);
959         Field field=getField(info,true);
960
961         if (field!=null)
962         {
963             old=field._value;
964             while(field!=null)
965             {
966                 field.clear();
967                 field=field._next;
968             }
969         }
970         
971         return old;
972     }
973    
974     /* -------------------------------------------------------------- */
975     /** Get a header as an integer value.
976      * Returns the value of an integer field or -1 if not found.
977      * The case of the field name is ignored.
978      * @param name the case-insensitive field name
979      * @exception NumberFormatException If bad integer found
980      */

981     public int getIntField(String JavaDoc name)
982         throws NumberFormatException JavaDoc
983     {
984         String JavaDoc val = valueParameters(get(name),null);
985         if (val!=null)
986             return Integer.parseInt(val);
987         return -1;
988     }
989     
990     /* -------------------------------------------------------------- */
991     /** Get a header as a date value.
992      * Returns the value of a date field, or -1 if not found.
993      * The case of the field name is ignored.
994      * @param name the case-insensitive field name
995      */

996     public long getDateField(String JavaDoc name)
997     {
998         String JavaDoc val = valueParameters(get(name),null);
999         if (val==null)
1000            return -1;
1001
1002        if (_dateReceive==null)
1003       {
1004               _dateReceive=(SimpleDateFormat JavaDoc[])__dateReceiveCache.get();
1005               if (_dateReceive==null)
1006               {
1007                    _dateReceive=(SimpleDateFormat JavaDoc[]) new SimpleDateFormat JavaDoc[__dateReceiveSource.length];
1008                    __dateReceiveCache.set(_dateReceive);
1009               }
1010       }
1011       
1012        for (int i=0;i<_dateReceive.length;i++)
1013        {
1014            // clone formatter for thread safety
1015
if (_dateReceive[i]==null)
1016                _dateReceive[i]=(SimpleDateFormat JavaDoc)__dateReceiveSource[i].clone();
1017            
1018            try{
1019                Date JavaDoc date=(Date JavaDoc)_dateReceive[i].parseObject(val);
1020                return date.getTime();
1021            }
1022            catch(java.lang.Exception JavaDoc e)
1023            {
1024                LogSupport.ignore(log,e);
1025            }
1026        }
1027        if (val.endsWith(" GMT"))
1028        {
1029            val=val.substring(0,val.length()-4);
1030            for (int i=0;i<_dateReceive.length;i++)
1031            {
1032                try{
1033                    Date JavaDoc date=(Date JavaDoc)_dateReceive[i].parseObject(val);
1034                    return date.getTime();
1035                }
1036                catch(java.lang.Exception JavaDoc e)
1037                {
1038                    LogSupport.ignore(log,e);
1039                }
1040            }
1041        }
1042
1043        throw new IllegalArgumentException JavaDoc(val);
1044    }
1045    
1046    /* -------------------------------------------------------------- */
1047    /**
1048     * Sets the value of an integer field.
1049     * @param name the field name
1050     * @param value the field integer value
1051     */

1052    public void putIntField(String JavaDoc name, int value)
1053    {
1054        put(name, Integer.toString(value));
1055    }
1056
1057    /* -------------------------------------------------------------- */
1058    /**
1059     * Sets the value of a date field.
1060     * @param name the field name
1061     * @param date the field date value
1062     */

1063    public void putDateField(String JavaDoc name, Date JavaDoc date)
1064    {
1065        putDateField(name,date.getTime());
1066    }
1067    
1068    /* -------------------------------------------------------------- */
1069    /**
1070     * Adds the value of a date field.
1071     * @param name the field name
1072     * @param date the field date value
1073     */

1074    public void addDateField(String JavaDoc name, Date JavaDoc date)
1075    {
1076        addDateField(name,date.getTime());
1077    }
1078    
1079    /* -------------------------------------------------------------- */
1080    /**
1081     * Adds the value of a date field.
1082     * @param name the field name
1083     * @param date the field date value
1084     */

1085    public void addDateField(String JavaDoc name, long date)
1086    {
1087        if (_dateBuffer==null)
1088        {
1089            _dateBuffer=new StringBuffer JavaDoc(32);
1090            _calendar=new HttpCal();
1091        }
1092        _dateBuffer.setLength(0);
1093        _calendar.setTimeInMillis(date);
1094        formatDate(_dateBuffer, _calendar, false);
1095        add(name, _dateBuffer.toString());
1096    }
1097    
1098    /* -------------------------------------------------------------- */
1099    /**
1100     * Sets the value of a date field.
1101     * @param name the field name
1102     * @param date the field date value
1103     */

1104    public void putDateField(String JavaDoc name, long date)
1105    {
1106        if (_dateBuffer==null)
1107        {
1108            _dateBuffer=new StringBuffer JavaDoc(32);
1109            _calendar=new HttpCal();
1110        }
1111        _dateBuffer.setLength(0);
1112        _calendar.setTimeInMillis(date);
1113        formatDate(_dateBuffer, _calendar, false);
1114        put(name, _dateBuffer.toString());
1115    }
1116
1117    /* -------------------------------------------------------------- */
1118    /** Read HttpHeaders from inputStream.
1119     */

1120    public void read(LineInput in)
1121        throws IOException JavaDoc
1122    {
1123        Field last=null;
1124        char[] buf=null;
1125        int size=0;
1126        org.mortbay.util.LineInput.LineBuffer line_buffer;
1127        synchronized(in)
1128        {
1129            line:
1130            while ((line_buffer=in.readLineBuffer())!=null)
1131            {
1132                // check space in the lowercase buffer
1133
buf=line_buffer.buffer;
1134                size=line_buffer.size;
1135                if (size==0)
1136                    break;
1137                
1138                // setup loop state machine
1139
int i1=-1;
1140                int i2=-1;
1141                int name_l=0;
1142                int i=0;
1143                char c=buf[0];
1144                
1145                // Check for continuity line
1146
if (c!=' ' && c!='\t')
1147                {
1148                    i2=0;
1149                    // reading name upto :
1150
for (i=1;i<size;i++)
1151                    {
1152                        c=buf[i];
1153                        if (c==':')
1154                        {
1155                            name_l=i2+1;
1156                            break;
1157                        }
1158                        
1159                        if (c!=' '&&c!='\t')
1160                            i2=i;
1161                    }
1162                }
1163
1164                // skip whitespace after : or start of continuity line
1165
for (i++;i<size;i++)
1166                {
1167                    c=buf[i];
1168                    if (c!=' ' && c!='\t')
1169                    {
1170                        i1=i;
1171                        i2=i-1;
1172                        break;
1173                    }
1174                }
1175                
1176                // Reverse Parse the "name : value" to last char of value
1177
for (i=size;i-->i1 && i>=0;)
1178                {
1179                    c=buf[i];
1180                    if (c!=' ' && c!='\t')
1181                    {
1182                        i2=i;
1183                        break;
1184                    }
1185                }
1186
1187                // If no name, it is a continuation line
1188
if (name_l<=0)
1189                {
1190                    if (i1>0 && last!=null)
1191                        last._value=last._value+' '+new String JavaDoc(buf,i1,i2-i1+1);
1192                    continue;
1193                }
1194
1195                // create the field.
1196
FieldInfo info = getFieldInfo(buf,0,name_l);
1197                Field field=getField(info,false);
1198                last=null;
1199                if (field!=null)
1200                {
1201                    while(field!=null && field._version==_version)
1202                    {
1203                        last=field;
1204                        field=field._next;
1205                    }
1206                }
1207                
1208                if (field!=null)
1209                {
1210                    if (i1>=0)
1211                        field.reset(buf,i1,i2-i1+1,_version);
1212                    else
1213                        field.reset("",_version);
1214                }
1215                else
1216                {
1217                    // create the field
1218
if (i1>=0)
1219                        field=new Field(info,buf,i1,i2-i1+1,_version);
1220                    else
1221                        field=new Field(info,"",_version);
1222                    
1223                    // look for chain to add too
1224
if(last!=null)
1225                    {
1226                        field._prev=last;
1227                        last._next=field;
1228                          
1229                    }
1230                    else if (info.hashCode()<_index.length)
1231                        _index[info.hashCode()]=_fields.size();
1232                    _fields.add(field);
1233                }
1234                
1235                last=field;
1236            }
1237        }
1238    }
1239
1240    
1241    /* -------------------------------------------------------------- */
1242    /* Write Extra HTTP headers.
1243     */

1244    public void write(Writer JavaDoc writer)
1245        throws IOException JavaDoc
1246    {
1247        synchronized(writer)
1248        {
1249            for (int i=0;i<_fields.size();i++)
1250            {
1251                Field field=(Field)_fields.get(i);
1252                if (field!=null)
1253                    field.write(writer,_version);
1254            }
1255            writer.write(__CRLF);
1256        }
1257    }
1258    
1259    
1260    /* -------------------------------------------------------------- */
1261    public String JavaDoc toString()
1262    {
1263        try
1264        {
1265            StringWriter JavaDoc writer = new StringWriter JavaDoc();
1266            write(writer);
1267            return writer.toString();
1268        }
1269        catch(Exception JavaDoc e)
1270        {}
1271        return null;
1272    }
1273
1274    /* ------------------------------------------------------------ */
1275    /** Clear the header.
1276     */

1277    public void clear()
1278    {
1279        _version++;
1280        if (_version>1000)
1281        {
1282            _version=0;
1283            for (int i=_fields.size();i-->0;)
1284            {
1285                Field field=(Field)_fields.get(i);
1286                if (field!=null)
1287                    field.clear();
1288            }
1289        }
1290    }
1291    
1292    /* ------------------------------------------------------------ */
1293    /** Destroy the header.
1294     * Help the garbage collector by null everything that we can.
1295     */

1296    public void destroy()
1297    {
1298        for (int i=_fields.size();i-->0;)
1299        {
1300            Field field=(Field)_fields.get(i);
1301            if (field!=null)
1302                field.destroy();
1303        }
1304        _fields=null;
1305        _index=null;
1306        _dateBuffer=null;
1307        _calendar=null;
1308        _dateReceive=null;
1309    }
1310    
1311    /* ------------------------------------------------------------ */
1312    /** Get field value parameters.
1313     * Some field values can have parameters. This method separates
1314     * the value from the parameters and optionally populates a
1315     * map with the paramters. For example:<PRE>
1316     * FieldName : Value ; param1=val1 ; param2=val2
1317     * </PRE>
1318     * @param value The Field value, possibly with parameteres.
1319     * @param parameters A map to populate with the parameters, or null
1320     * @return The value.
1321     */

1322    public static String JavaDoc valueParameters(String JavaDoc value, Map JavaDoc parameters)
1323    {
1324        if (value==null)
1325            return null;
1326        
1327        int i = value.indexOf(';');
1328        if (i<0)
1329            return value;
1330        if (parameters==null)
1331            return value.substring(0,i).trim();
1332
1333        StringTokenizer JavaDoc tok1 =
1334            new QuotedStringTokenizer(value.substring(i),";",false,true);
1335        while(tok1.hasMoreTokens())
1336        {
1337            String JavaDoc token=tok1.nextToken();
1338            StringTokenizer JavaDoc tok2 =
1339                new QuotedStringTokenizer(token,"= ");
1340            if (tok2.hasMoreTokens())
1341            {
1342                String JavaDoc paramName=tok2.nextToken();
1343                String JavaDoc paramVal=null;
1344                if (tok2.hasMoreTokens())
1345                    paramVal=tok2.nextToken();
1346                parameters.put(paramName,paramVal);
1347            }
1348        }
1349        
1350        return value.substring(0,i).trim();
1351    }
1352
1353    /* ------------------------------------------------------------ */
1354    public static Float JavaDoc getQuality(String JavaDoc value)
1355    {
1356        if (value==null)
1357            return __zero;
1358        
1359        int qe=value.indexOf(";");
1360        if (qe++<0 || qe==value.length())
1361            return __one;
1362        
1363        if (value.charAt(qe++)=='q')
1364        {
1365            qe++;
1366            Map.Entry JavaDoc entry=__qualities.getEntry(value,qe,value.length()-qe);
1367            if (entry!=null)
1368                return (Float JavaDoc)entry.getValue();
1369        }
1370        
1371        HashMap JavaDoc params = new HashMap JavaDoc(3);
1372        valueParameters(value,params);
1373        String JavaDoc qs=(String JavaDoc)params.get("q");
1374        Float JavaDoc q=(Float JavaDoc)__qualities.get(qs);
1375        if (q==null)
1376        {
1377            try{q=new Float JavaDoc(qs);}
1378            catch(Exception JavaDoc e){q=__one;}
1379        }
1380        return q;
1381    }
1382
1383    /* ------------------------------------------------------------ */
1384    /** List values in quality order.
1385     * @param enm Enumeration of values with quality parameters
1386     * @return values in quality order.
1387     */

1388    public static List JavaDoc qualityList(Enumeration JavaDoc enm)
1389    {
1390        if(enm==null || !enm.hasMoreElements())
1391            return Collections.EMPTY_LIST;
1392
1393        Object JavaDoc list=null;
1394        Object JavaDoc qual=null;
1395
1396        // Assume list will be well ordered and just add nonzero
1397
while(enm.hasMoreElements())
1398        {
1399            String JavaDoc v=enm.nextElement().toString();
1400            Float JavaDoc q=getQuality(v);
1401
1402            if (q.floatValue()>=0.001)
1403            {
1404                list=LazyList.add(list,v);
1405                qual=LazyList.add(qual,q);
1406            }
1407        }
1408
1409        List JavaDoc vl=LazyList.getList(list,false);
1410        if (vl.size()<2)
1411            return vl;
1412
1413        List JavaDoc ql=LazyList.getList(qual,false);
1414
1415        // sort list with swaps
1416
Float JavaDoc last=__zero;
1417        for (int i=vl.size();i-->0;)
1418        {
1419            Float JavaDoc q = (Float JavaDoc)ql.get(i);
1420            if (last.compareTo(q)>0)
1421            {
1422                Object JavaDoc tmp=vl.get(i);
1423                vl.set(i,vl.get(i+1));
1424                vl.set(i+1,tmp);
1425                ql.set(i,ql.get(i+1));
1426                ql.set(i+1,q);
1427                last=__zero;
1428                i=vl.size();
1429                continue;
1430            }
1431            last=q;
1432        }
1433        ql.clear();
1434        return vl;
1435    }
1436    
1437
1438
1439    /* ------------------------------------------------------------ */
1440    /** Format a set cookie value
1441     * @param cookie The cookie.
1442     */

1443    public void addSetCookie(Cookie JavaDoc cookie)
1444    {
1445        String JavaDoc name=cookie.getName();
1446        String JavaDoc value=cookie.getValue();
1447        int version=cookie.getVersion();
1448        
1449        // Check arguments
1450
if (name==null || name.length()==0)
1451            throw new IllegalArgumentException JavaDoc("Bad cookie name");
1452
1453        // Format value and params
1454
StringBuffer JavaDoc buf = new StringBuffer JavaDoc(128);
1455        String JavaDoc name_value_params=null;
1456        synchronized(buf)
1457        {
1458            buf.append(name);
1459            buf.append('=');
1460            if (value!=null && value.length()>0)
1461            {
1462                if (version==0)
1463                    URI.encodeString(buf,value,"\";, ");
1464                else
1465                    buf.append(QuotedStringTokenizer.quote(value,"\";, "));
1466            }
1467
1468            if (version>0)
1469            {
1470                buf.append(";Version=");
1471                buf.append(version);
1472                String JavaDoc comment=cookie.getComment();
1473                if (comment!=null && comment.length()>0)
1474                {
1475                    buf.append(";Comment=");
1476                    QuotedStringTokenizer.quote(buf,comment);
1477                }
1478            }
1479            String JavaDoc path=cookie.getPath();
1480            if (path!=null && path.length()>0)
1481            {
1482                buf.append(";Path=");
1483                buf.append(path);
1484            }
1485            String JavaDoc domain=cookie.getDomain();
1486            if (domain!=null && domain.length()>0)
1487            {
1488                buf.append(";Domain=");
1489                buf.append(domain.toLowerCase());// lowercase for IE
1490
}
1491            long maxAge = cookie.getMaxAge();
1492            if (maxAge>=0)
1493            {
1494                if (version==0)
1495                {
1496                    buf.append(";Expires=");
1497                    if (maxAge==0)
1498                        buf.append(__01Jan1970);
1499                    else
1500                        formatDate(buf,System.currentTimeMillis()+1000L*maxAge,true);
1501                }
1502                else
1503                {
1504                    buf.append (";Max-Age=");
1505                    buf.append (cookie.getMaxAge());
1506                }
1507            }
1508            else if (version>0)
1509            {
1510                buf.append (";Discard");
1511            }
1512            if (cookie.getSecure())
1513            {
1514                buf.append(";Secure");
1515            }
1516            if (cookie instanceof HttpOnlyCookie)
1517                buf.append(";HttpOnly");
1518            
1519            name_value_params = buf.toString();
1520        }
1521        put(__Expires,__01Jan1970);
1522        add(__SetCookie,name_value_params);
1523    }
1524
1525    /* ------------------------------------------------------------ */
1526    /** Add fields from another HttpFields instance.
1527     * Single valued fields are replaced, while all others are added.
1528     * @param fields
1529     */

1530    public void add(HttpFields fields)
1531    {
1532        if (fields==null)
1533            return;
1534
1535        Enumeration JavaDoc enm = fields.getFieldNames();
1536        while( enm.hasMoreElements() )
1537        {
1538            String JavaDoc name = (String JavaDoc)enm.nextElement();
1539            Enumeration JavaDoc values = fields.getValues(name);
1540            while(values.hasMoreElements())
1541                add(name,(String JavaDoc)values.nextElement());
1542        }
1543    }
1544
1545    /* ------------------------------------------------------------ */
1546    /**
1547     * return an iterator for field name:value pairs
1548     * @return an HttpFields.Iterator
1549     */

1550    public Iterator JavaDoc iterator() {return new EntryIterator();}
1551
1552    
1553    /* ------------------------------------------------------------ */
1554    /* ------------------------------------------------------------ */
1555    public class Entry
1556    {
1557        protected int _i;
1558        
1559        Entry(int i) {_i=i;}
1560        public String JavaDoc getKey() {return ((Field)_fields.get(_i)).getDisplayName();}
1561        public String JavaDoc getValue() {return ((Field)_fields.get(_i))._value;}
1562    }
1563
1564    /* ------------------------------------------------------------ */
1565    /* ------------------------------------------------------------ */
1566    private class EntryIterator implements Iterator JavaDoc
1567    {
1568        protected int _i=0;
1569        public boolean hasNext() {return (_i<_fields.size());}
1570        public Object JavaDoc next() throws NoSuchElementException JavaDoc {return new Entry(_i++);}
1571        public void remove() { throw new UnsupportedOperationException JavaDoc();}
1572    }
1573
1574    /* ------------------------------------------------------------ */
1575    /* ------------------------------------------------------------ */
1576    /* handle 1.3 protected methods */
1577    private static class HttpCal extends GregorianCalendar JavaDoc
1578    {
1579        HttpCal()
1580        {
1581            super(__GMT);
1582        }
1583
1584        /* ------------------------------------------------------------------------------- */
1585        /**
1586         * @see java.util.Calendar#setTimeInMillis(long)
1587         */

1588        public void setTimeInMillis(long arg0)
1589        {
1590            super.setTimeInMillis(arg0);
1591        }
1592        /* ------------------------------------------------------------------------------- */
1593        /**
1594         * @see java.util.Calendar#getTimeInMillis()
1595         */

1596        public long getTimeInMillis()
1597        {
1598            return super.getTimeInMillis();
1599        }
1600    }
1601}
1602
Popular Tags