KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > burlap > client > MicroBurlapInput


1 /*
2  * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
3  *
4  * The Apache Software License, Version 1.1
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution, if
19  * any, must include the following acknowlegement:
20  * "This product includes software developed by the
21  * Caucho Technology (http://www.caucho.com/)."
22  * Alternately, this acknowlegement may appear in the software itself,
23  * if and wherever such third-party acknowlegements normally appear.
24  *
25  * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * info@caucho.com.
29  *
30  * 5. Products derived from this software may not be called "Resin"
31  * nor may "Resin" appear in their names without prior written
32  * permission of Caucho Technology.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
38  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
44  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  *
46  * @author Scott Ferguson
47  */

48
49 package com.caucho.burlap.client;
50
51 import java.io.ByteArrayOutputStream JavaDoc;
52 import java.io.IOException JavaDoc;
53 import java.io.InputStream JavaDoc;
54 import java.util.Calendar JavaDoc;
55 import java.util.Date JavaDoc;
56 import java.util.Hashtable JavaDoc;
57 import java.util.TimeZone JavaDoc;
58 import java.util.Vector JavaDoc;
59
60 /**
61  * Input stream for Burlap requests, compatible with microedition
62  * Java. It only uses classes and types available to J2ME. In
63  * particular, it does not have any support for the <double> type.
64  *
65  * <p>MicroBurlapInput does not depend on any classes other than
66  * in J2ME, so it can be extracted independently into a smaller package.
67  *
68  * <p>MicroBurlapInput is unbuffered, so any client needs to provide
69  * its own buffering.
70  *
71  * <pre>
72  * InputStream is = ...; // from http connection
73  * MicroBurlapInput in = new MicroBurlapInput(is);
74  * String value;
75  *
76  * in.startReply(); // read reply header
77  * value = in.readString(); // read string value
78  * in.completeReply(); // read reply footer
79  * </pre>
80  */

81 public class MicroBurlapInput {
82   private static int base64Decode[];
83   
84   private InputStream JavaDoc is;
85   protected int peek;
86   protected boolean peekTag;
87   protected Date JavaDoc date;
88   protected Calendar JavaDoc utcCalendar;
89   private Calendar JavaDoc localCalendar;
90   protected Vector JavaDoc refs;
91   protected String JavaDoc method;
92   protected StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
93   protected StringBuffer JavaDoc entity = new StringBuffer JavaDoc();
94
95   /**
96    * Creates a new Burlap input stream, initialized with an
97    * underlying input stream.
98    *
99    * @param is the underlying input stream.
100    */

101   public MicroBurlapInput(InputStream JavaDoc is)
102   {
103     init(is);
104   }
105
106   /**
107    * Creates an uninitialized Burlap input stream.
108    */

109   public MicroBurlapInput()
110   {
111   }
112
113   /**
114    * Returns a call's method.
115    */

116   public String JavaDoc getMethod()
117   {
118     return method;
119   }
120
121   /**
122    * Initialize the Burlap input stream with a new underlying stream.
123    * Applications can use <code>init(InputStream)</code> to reuse
124    * MicroBurlapInput to save garbage collection.
125    */

126   public void init(InputStream JavaDoc is)
127   {
128     this.is = is;
129     this.refs = null;
130   }
131
132   /**
133    * Starts reading the call
134    *
135    * <p>A successful completion will have a single value:
136    *
137    * <pre>
138    * &lt;burlap:call>
139    * &lt;method>method&lt;/method>
140    * </pre>
141    */

142   public void startCall()
143     throws IOException JavaDoc
144   {
145     expectStartTag("burlap:call");
146     expectStartTag("method");
147     method = parseString();
148     expectEndTag("method");
149     this.refs = null;
150   }
151
152   /**
153    * Completes reading the call.
154    *
155    * <pre>
156    * &lt;/burlap:call>
157    * </pre>
158    */

159   public void completeCall()
160     throws IOException JavaDoc
161   {
162     expectEndTag("burlap:call");
163   }
164
165   /**
166    * Reads a reply as an object.
167    * If the reply has a fault, throws the exception.
168    */

169   public Object JavaDoc readReply(Class JavaDoc expectedClass)
170     throws Exception JavaDoc
171   {
172     if (startReply()) {
173       Object JavaDoc value = readObject(expectedClass);
174       completeReply();
175       return value;
176     }
177     else {
178       Hashtable JavaDoc fault = readFault();
179
180       Object JavaDoc detail = fault.get("detail");
181       if (detail instanceof Exception JavaDoc)
182         throw (Exception JavaDoc) detail;
183
184       else {
185         String JavaDoc code = (String JavaDoc) fault.get("code");
186         String JavaDoc message = (String JavaDoc) fault.get("message");
187         
188         throw new BurlapServiceException(message, code, detail);
189       }
190     }
191   }
192
193   /**
194    * Starts reading the reply.
195    *
196    * <p>A successful completion will have a single value. An unsuccessful
197    * one will have a fault:
198    *
199    * <pre>
200    * &lt;burlap:reply>
201    * </pre>
202    *
203    * @return true if success, false for fault.
204    */

205   public boolean startReply()
206     throws IOException JavaDoc
207   {
208     this.refs = null;
209     
210     expectStartTag("burlap:reply");
211
212     if (! parseTag())
213       throw new BurlapProtocolException("expected <value>");
214
215     String JavaDoc tag = sbuf.toString();
216     if (tag.equals("fault")) {
217       peekTag = true;
218       return false;
219     }
220     else {
221       peekTag = true;
222       return true;
223     }
224   }
225
226   /**
227    * Completes reading the reply.
228    *
229    * <pre>
230    * &lt;/burlap:reply>
231    * </pre>
232    */

233   public void completeReply()
234     throws IOException JavaDoc
235   {
236     expectEndTag("burlap:reply");
237   }
238
239   /**
240    * Reads a boolean value from the input stream.
241    */

242   public boolean readBoolean()
243     throws IOException JavaDoc
244   {
245     expectStartTag("boolean");
246
247     int value = parseInt();
248     
249     expectEndTag("boolean");
250
251     return value != 0;
252   }
253
254   /**
255    * Reads an integer value from the input stream.
256    */

257   public int readInt()
258     throws IOException JavaDoc
259   {
260     expectStartTag("int");
261
262     int value = parseInt();
263     
264     expectEndTag("int");
265
266     return value;
267   }
268
269   /**
270    * Reads a long value from the input stream.
271    */

272   public long readLong()
273     throws IOException JavaDoc
274   {
275     expectStartTag("long");
276
277     long value = parseLong();
278     
279     expectEndTag("long");
280
281     return value;
282   }
283
284   /**
285    * Reads a date value from the input stream.
286    */

287   public long readUTCDate()
288     throws IOException JavaDoc
289   {
290     expectStartTag("date");
291
292     if (utcCalendar == null)
293       utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
294
295     long value = parseDate(utcCalendar);
296     
297     expectEndTag("date");
298
299     return value;
300   }
301
302   /**
303    * Reads a date value from the input stream.
304    */

305   public long readLocalDate()
306     throws IOException JavaDoc
307   {
308     expectStartTag("date");
309
310     if (localCalendar == null)
311       localCalendar = Calendar.getInstance();
312
313     long value = parseDate(localCalendar);
314     
315     expectEndTag("date");
316
317     return value;
318   }
319
320   /**
321    * Reads a remote value from the input stream.
322    */

323   public BurlapRemote readRemote()
324     throws IOException JavaDoc
325   {
326     expectStartTag("remote");
327
328     String JavaDoc type = readType();
329     String JavaDoc url = readString();
330     
331     expectEndTag("remote");
332
333     return new BurlapRemote(type, url);
334   }
335
336   /**
337    * Reads a string value from the input stream.
338    *
339    * <p>The two valid possibilities are either a &lt;null>
340    * or a &lt;string>. The string value is encoded in utf-8, and
341    * understands the basic XML escapes: "&123;", "&lt;", "&gt;",
342    * "&apos;", "&quot;".
343    *
344    * <pre>
345    * &lt;null>&lt;/null>
346    * &lt;string>a utf-8 encoded string&lt;/string>
347    * </pre>
348    */

349   public String JavaDoc readString()
350     throws IOException JavaDoc
351   {
352     if (! parseTag())
353       throw new BurlapProtocolException("expected <string>");
354
355     String JavaDoc tag = sbuf.toString();
356     if (tag.equals("null")) {
357       expectEndTag("null");
358       return null;
359     }
360     else if (tag.equals("string")) {
361       sbuf.setLength(0);
362       parseString(sbuf);
363       String JavaDoc value = sbuf.toString();
364       expectEndTag("string");
365       return value;
366     }
367     else
368       throw expectBeginTag("string", tag);
369   }
370
371   /**
372    * Reads a byte array from the input stream.
373    *
374    * <p>The two valid possibilities are either a &lt;null>
375    * or a &lt;base64>.
376    */

377   public byte []readBytes()
378     throws IOException JavaDoc
379   {
380     if (! parseTag())
381       throw new BurlapProtocolException("expected <base64>");
382
383     String JavaDoc tag = sbuf.toString();
384     if (tag.equals("null")) {
385       expectEndTag("null");
386       return null;
387     }
388     else if (tag.equals("base64")) {
389       sbuf.setLength(0);
390       byte []value = parseBytes();
391       expectEndTag("base64");
392       return value;
393     }
394     else
395       throw expectBeginTag("base64", tag);
396   }
397
398   /**
399    * Reads an arbitrary object the input stream.
400    */

401   public Object JavaDoc readObject(Class JavaDoc expectedClass)
402     throws IOException JavaDoc
403   {
404     if (! parseTag())
405       throw new BurlapProtocolException("expected <tag>");
406
407     String JavaDoc tag = sbuf.toString();
408     if (tag.equals("null")) {
409       expectEndTag("null");
410       return null;
411     }
412     else if (tag.equals("boolean")) {
413       int value = parseInt();
414       expectEndTag("boolean");
415       return new Boolean JavaDoc(value != 0);
416     }
417     else if (tag.equals("int")) {
418       int value = parseInt();
419       expectEndTag("int");
420       return new Integer JavaDoc(value);
421     }
422     else if (tag.equals("long")) {
423       long value = parseLong();
424       expectEndTag("long");
425       return new Long JavaDoc(value);
426     }
427     else if (tag.equals("string")) {
428       sbuf.setLength(0);
429       parseString(sbuf);
430       String JavaDoc value = sbuf.toString();
431       expectEndTag("string");
432       return value;
433     }
434     else if (tag.equals("xml")) {
435       sbuf.setLength(0);
436       parseString(sbuf);
437       String JavaDoc value = sbuf.toString();
438       expectEndTag("xml");
439       return value;
440     }
441     else if (tag.equals("date")) {
442       if (utcCalendar == null)
443         utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
444       
445       long value = parseDate(utcCalendar);
446       expectEndTag("date");
447       return new Date JavaDoc(value);
448     }
449     else if (tag.equals("map")) {
450       String JavaDoc type = readType();
451
452       return readMap(expectedClass, type);
453     }
454     else if (tag.equals("list")) {
455       String JavaDoc type = readType();
456       
457       int length = readLength();
458
459       return readList(expectedClass, type, length);
460     }
461     else if (tag.equals("ref")) {
462       int value = parseInt();
463       expectEndTag("ref");
464
465       return refs.elementAt(value);
466     }
467     else if (tag.equals("remote")) {
468       String JavaDoc type = readType();
469       String JavaDoc url = readString();
470
471       expectEndTag("remote");
472
473       return resolveRemote(type, url);
474     }
475     else
476       return readExtensionObject(expectedClass, tag);
477   }
478
479   /**
480    * Reads a type value from the input stream.
481    *
482    * <pre>
483    * &lt;type>a utf-8 encoded string&lt;/type>
484    * </pre>
485    */

486   public String JavaDoc readType()
487     throws IOException JavaDoc
488   {
489     if (! parseTag())
490       throw new BurlapProtocolException("expected <type>");
491
492     String JavaDoc tag = sbuf.toString();
493     if (! tag.equals("type"))
494       throw new BurlapProtocolException("expected <type>");
495     
496     sbuf.setLength(0);
497     parseString(sbuf);
498     String JavaDoc value = sbuf.toString();
499     expectEndTag("type");
500     
501     return value;
502   }
503
504   /**
505    * Reads a length value from the input stream. If the length isn't
506    * specified, returns -1.
507    *
508    * <pre>
509    * &lt;length>integer&lt;/length>
510    * </pre>
511    */

512   public int readLength()
513     throws IOException JavaDoc
514   {
515     expectStartTag("length");
516
517     int ch = skipWhitespace();
518
519     peek = ch;
520     
521     if (ch == '<') {
522       expectEndTag("length");
523       return -1;
524     }
525
526     int value = parseInt();
527       
528     expectEndTag("length");
529     
530     return value;
531   }
532
533   /**
534    * Resolves a remote object.
535    */

536   public Object JavaDoc resolveRemote(String JavaDoc type, String JavaDoc url)
537     throws IOException JavaDoc
538   {
539     return new BurlapRemote(type, url);
540   }
541
542   /**
543    * Reads a fault.
544    */

545   public Hashtable JavaDoc readFault()
546     throws IOException JavaDoc
547   {
548     expectStartTag("fault");
549     
550     Hashtable JavaDoc map = new Hashtable JavaDoc();
551
552     while (parseTag()) {
553       peekTag = true;
554       Object JavaDoc key = readObject(null);
555       Object JavaDoc value = readObject(null);
556
557       if (key != null && value != null)
558         map.put(key, value);
559     }
560     
561     if (! sbuf.toString().equals("fault"))
562       throw new BurlapProtocolException("expected </fault>");
563
564     return map;
565   }
566   
567   /**
568    * Reads an object from the input stream.
569    *
570    * @param expectedClass the calling routine's expected class
571    * @param type the type from the stream
572    */

573   public Object JavaDoc readMap(Class JavaDoc expectedClass, String JavaDoc type)
574     throws IOException JavaDoc
575   {
576     Hashtable JavaDoc map = new Hashtable JavaDoc();
577     if (refs == null)
578       refs = new Vector JavaDoc();
579     refs.addElement(map);
580
581     while (parseTag()) {
582       peekTag = true;
583       Object JavaDoc key = readObject(null);
584       Object JavaDoc value = readObject(null);
585
586       map.put(key, value);
587     }
588     if (! sbuf.toString().equals("map"))
589       throw new BurlapProtocolException("expected </map>");
590
591     return map;
592   }
593
594   /**
595    * Reads object unknown to MicroBurlapInput.
596    */

597   protected Object JavaDoc readExtensionObject(Class JavaDoc expectedClass, String JavaDoc tag)
598     throws IOException JavaDoc
599   {
600     throw new BurlapProtocolException("unknown object tag <" + tag + ">");
601   }
602   
603   /**
604    * Reads a list object from the input stream.
605    *
606    * @param expectedClass the calling routine's expected class
607    * @param type the type from the stream
608    * @param length the expected length, -1 for unspecified length
609    */

610   public Object JavaDoc readList(Class JavaDoc expectedClass, String JavaDoc type, int length)
611     throws IOException JavaDoc
612   {
613     Vector JavaDoc list = new Vector JavaDoc();
614     if (refs == null)
615       refs = new Vector JavaDoc();
616     refs.addElement(list);
617
618     while (parseTag()) {
619       peekTag = true;
620       Object JavaDoc value = readObject(null);
621
622       list.addElement(value);
623     }
624     
625     if (! sbuf.toString().equals("list"))
626       throw new BurlapProtocolException("expected </list>");
627
628     return list;
629   }
630
631   /**
632    * Parses an integer value from the stream.
633    */

634   protected int parseInt()
635     throws IOException JavaDoc
636   {
637     int sign = 1;
638     int value = 0;
639
640     int ch = skipWhitespace();
641     if (ch == '+')
642       ch = read();
643     else if (ch == '-') {
644       sign = -1;
645       ch = read();
646     }
647
648     for (; ch >= '0' && ch <= '9'; ch = read())
649       value = 10 * value + ch - '0';
650     
651     peek = ch;
652
653     return sign * value;
654   }
655
656   /**
657    * Parses a long value from the stream.
658    */

659   protected long parseLong()
660     throws IOException JavaDoc
661   {
662     long sign = 1;
663     long value = 0;
664
665     int ch = skipWhitespace();
666     if (ch == '+')
667       ch = read();
668     else if (ch == '-') {
669       sign = -1;
670       ch = read();
671     }
672
673     for (; ch >= '0' && ch <= '9'; ch = read()) {
674       value = 10 * value + ch - '0';
675     }
676
677     peek = ch;
678
679     return sign * value;
680   }
681
682   /**
683    * Parses a date value from the stream.
684    */

685   protected long parseDate(Calendar JavaDoc calendar)
686     throws IOException JavaDoc
687   {
688     int ch = skipWhitespace();
689     
690     int year = 0;
691     for (int i = 0; i < 4; i++) {
692       if (ch >= '0' && ch <= '9')
693         year = 10 * year + ch - '0';
694       else
695         throw expectedChar("year", ch);
696
697       ch = read();
698     }
699
700     int month = 0;
701     for (int i = 0; i < 2; i++) {
702       if (ch >= '0' && ch <= '9')
703         month = 10 * month + ch - '0';
704       else
705         throw expectedChar("month", ch);
706
707       ch = read();
708     }
709
710     int day = 0;
711     for (int i = 0; i < 2; i++) {
712       if (ch >= '0' && ch <= '9')
713         day = 10 * day + ch - '0';
714       else
715         throw expectedChar("day", ch);
716
717       ch = read();
718     }
719
720     if (ch != 'T')
721       throw expectedChar("`T'", ch);
722
723     ch = read();
724
725     int hour = 0;
726     for (int i = 0; i < 2; i++) {
727       if (ch >= '0' && ch <= '9')
728         hour = 10 * hour + ch - '0';
729       else
730         throw expectedChar("hour", ch);
731
732       ch = read();
733     }
734
735     int minute = 0;
736     for (int i = 0; i < 2; i++) {
737       if (ch >= '0' && ch <= '9')
738         minute = 10 * minute + ch - '0';
739       else
740         throw expectedChar("minute", ch);
741
742       ch = read();
743     }
744
745     int second = 0;
746     for (int i = 0; i < 2; i++) {
747       if (ch >= '0' && ch <= '9')
748         second = 10 * second + ch - '0';
749       else
750         throw expectedChar("second", ch);
751
752       ch = read();
753     }
754
755     for (; ch > 0 && ch != '<'; ch = read()) {
756     }
757
758     peek = ch;
759
760     calendar.set(Calendar.YEAR, year);
761     calendar.set(Calendar.MONTH, month - 1);
762     calendar.set(Calendar.DAY_OF_MONTH, day);
763     calendar.set(Calendar.HOUR_OF_DAY, hour);
764     calendar.set(Calendar.MINUTE, minute);
765     calendar.set(Calendar.SECOND, second);
766     calendar.set(Calendar.MILLISECOND, 0);
767
768     return calendar.getTime().getTime();
769   }
770
771   /**
772    * Parses a string value from the stream.
773    * string buffer is used for the result.
774    */

775   protected String JavaDoc parseString()
776     throws IOException JavaDoc
777   {
778     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
779
780     return parseString(sbuf).toString();
781   }
782   
783   /**
784    * Parses a string value from the stream. The burlap object's
785    * string buffer is used for the result.
786    */

787   protected StringBuffer JavaDoc parseString(StringBuffer JavaDoc sbuf)
788     throws IOException JavaDoc
789   {
790     int ch = read();
791
792     for (; ch >= 0 && ch != '<'; ch = read()) {
793       if (ch == '&') {
794         ch = read();
795
796         if (ch == '#') {
797           ch = read();
798
799           if (ch >= '0' && ch <= '9') {
800             int v = 0;
801             for (; ch >= '0' && ch <= '9'; ch = read()) {
802               v = 10 * v + ch - '0';
803             }
804
805             sbuf.append((char) v);
806           }
807         }
808         else {
809           StringBuffer JavaDoc entityBuffer = new StringBuffer JavaDoc();
810
811           for (; ch >= 'a' && ch <= 'z'; ch = read())
812             entityBuffer.append((char) ch);
813
814           String JavaDoc entity = entityBuffer.toString();
815           if (entity.equals("amp"))
816             sbuf.append('&');
817           else if (entity.equals("apos"))
818             sbuf.append('\'');
819           else if (entity.equals("quot"))
820             sbuf.append('"');
821           else if (entity.equals("lt"))
822             sbuf.append('<');
823           else if (entity.equals("gt"))
824             sbuf.append('>');
825           else
826             throw new BurlapProtocolException("unknown XML entity &" + entity + "; at `" + (char) ch + "'");
827         }
828
829         if (ch != ';')
830           throw expectedChar("';'", ch);
831       }
832       else if (ch < 0x80)
833         sbuf.append((char) ch);
834       else if ((ch & 0xe0) == 0xc0) {
835         int ch1 = read();
836         int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
837
838         sbuf.append((char) v);
839       }
840       else if ((ch & 0xf0) == 0xe0) {
841         int ch1 = read();
842         int ch2 = read();
843         int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f);
844
845         sbuf.append((char) v);
846       }
847       else
848         throw new BurlapProtocolException("bad utf-8 encoding");
849     }
850
851     peek = ch;
852
853     return sbuf;
854   }
855   
856   /**
857    * Parses a byte array.
858    */

859   protected byte []parseBytes()
860     throws IOException JavaDoc
861   {
862     ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
863
864     parseBytes(bos);
865
866     return bos.toByteArray();
867   }
868   
869   /**
870    * Parses a byte array.
871    */

872   protected ByteArrayOutputStream JavaDoc parseBytes(ByteArrayOutputStream JavaDoc bos)
873     throws IOException JavaDoc
874   {
875     int ch;
876     for (ch = read(); ch >= 0 && ch != '<'; ch = read()) {
877       int b1 = ch;
878       int b2 = read();
879       int b3 = read();
880       int b4 = read();
881
882       if (b4 != '=') {
883         int chunk = ((base64Decode[b1] << 18) +
884                      (base64Decode[b2] << 12) +
885                      (base64Decode[b3] << 6) +
886                      (base64Decode[b4]));
887
888         bos.write(chunk >> 16);
889         bos.write(chunk >> 8);
890         bos.write(chunk);
891       }
892       else if (b3 != '=') {
893         int chunk = ((base64Decode[b1] << 12) +
894                      (base64Decode[b2] << 6) +
895                      (base64Decode[b3]));
896
897         bos.write(chunk >> 8);
898         bos.write(chunk);
899       }
900       else {
901         int chunk = ((base64Decode[b1] << 6) +
902                      (base64Decode[b2]));
903
904         bos.write(chunk);
905       }
906     }
907
908     if (ch == '<')
909       peek = ch;
910     
911     return bos;
912   }
913
914   protected void expectStartTag(String JavaDoc tag)
915     throws IOException JavaDoc
916   {
917     if (! parseTag())
918       throw new BurlapProtocolException("expected <" + tag + ">");
919
920     if (! sbuf.toString().equals(tag))
921       throw new BurlapProtocolException("expected <" + tag + "> at <" + sbuf + ">");
922   }
923
924   protected void expectEndTag(String JavaDoc tag)
925     throws IOException JavaDoc
926   {
927     if (parseTag())
928       throw new BurlapProtocolException("expected </" + tag + ">");
929
930     if (! sbuf.toString().equals(tag))
931       throw new BurlapProtocolException("expected </" + tag + "> at </" + sbuf + ">");
932   }
933
934   /**
935    * Parses a tag. Returns true if it's a start tag.
936    */

937   protected boolean parseTag()
938     throws IOException JavaDoc
939   {
940     if (peekTag) {
941       peekTag = false;
942       return true;
943     }
944     
945     int ch = skipWhitespace();
946     boolean isStartTag = true;
947
948     if (ch != '<')
949       throw expectedChar("'<'", ch);
950
951     ch = read();
952     if (ch == '/') {
953       isStartTag = false;
954       ch = is.read();
955     }
956     
957     if (! isTagChar(ch))
958       throw expectedChar("tag", ch);
959       
960     sbuf.setLength(0);
961     for (; isTagChar(ch); ch = read())
962       sbuf.append((char) ch);
963
964     if (ch != '>')
965       throw expectedChar("'>'", ch);
966
967     return isStartTag;
968   }
969
970   protected IOException JavaDoc expectedChar(String JavaDoc expect, int actualChar)
971   {
972     return new BurlapProtocolException("expected " + expect + " at " +
973                            (char) actualChar + "'");
974   }
975
976   protected IOException JavaDoc expectBeginTag(String JavaDoc expect, String JavaDoc tag)
977   {
978     return new BurlapProtocolException("expected <" + expect + "> at <" + tag + ">");
979   }
980
981   private boolean isTagChar(int ch)
982   {
983     return (ch >= 'a' && ch <= 'z' ||
984             ch >= 'A' && ch <= 'Z' ||
985             ch >= '0' && ch <= '9' ||
986             ch == ':' || ch == '-');
987   }
988
989   protected int skipWhitespace()
990     throws IOException JavaDoc
991   {
992     int ch = read();
993
994     for (;
995          ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
996          ch = read()) {
997     }
998
999     return ch;
1000  }
1001
1002  protected boolean isWhitespace(int ch)
1003    throws IOException JavaDoc
1004  {
1005    return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
1006  }
1007
1008  protected int read()
1009    throws IOException JavaDoc
1010  {
1011    if (peek > 0) {
1012      int value = peek;
1013      peek = 0;
1014      return value;
1015    }
1016    
1017    return is.read();
1018  }
1019
1020  static {
1021    base64Decode = new int[256];
1022    for (int i = 'A'; i <= 'Z'; i++)
1023      base64Decode[i] = i - 'A';
1024    for (int i = 'a'; i <= 'z'; i++)
1025      base64Decode[i] = i - 'a' + 26;
1026    for (int i = '0'; i <= '9'; i++)
1027      base64Decode[i] = i - '0' + 52;
1028    base64Decode['+'] = 62;
1029    base64Decode['/'] = 63;
1030  }
1031}
1032
Popular Tags