001    /*
002     * Copyright (c) 2001-2008 Caucho Technology, Inc.  All rights reserved.
003     *
004     * The Apache Software License, Version 1.1
005     *
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions
008     * are met:
009     *
010     * 1. Redistributions of source code must retain the above copyright
011     *    notice, this list of conditions and the following disclaimer.
012     *
013     * 2. Redistributions in binary form must reproduce the above copyright
014     *    notice, this list of conditions and the following disclaimer in
015     *    the documentation and/or other materials provided with the
016     *    distribution.
017     *
018     * 3. The end-user documentation included with the redistribution, if
019     *    any, must include the following acknowlegement:
020     *       "This product includes software developed by the
021     *        Caucho Technology (http://www.caucho.com/)."
022     *    Alternately, this acknowlegement may appear in the software itself,
023     *    if and wherever such third-party acknowlegements normally appear.
024     *
025     * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026     *    endorse or promote products derived from this software without prior
027     *    written permission. For written permission, please contact
028     *    info@caucho.com.
029     *
030     * 5. Products derived from this software may not be called "Resin"
031     *    nor may "Resin" appear in their names without prior written
032     *    permission of Caucho Technology.
033     *
034     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037     * DISCLAIMED.  IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039     * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040     * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041     * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044     * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045     *
046     * @author Scott Ferguson
047     */
048    
049    package com.caucho.burlap.io;
050    
051    import com.caucho.hessian.io.Deserializer;
052    import com.caucho.hessian.io.HessianRemoteResolver;
053    import com.caucho.hessian.io.SerializerFactory;
054    
055    import java.io.ByteArrayOutputStream;
056    import java.io.IOException;
057    import java.io.InputStream;
058    import java.io.Reader;
059    import java.lang.reflect.Field;
060    import java.util.ArrayList;
061    import java.util.Calendar;
062    import java.util.Date;
063    import java.util.HashMap;
064    import java.util.TimeZone;
065    
066    /**
067     * Input stream for Burlap requests.
068     *
069     * <p>BurlapInput is unbuffered, so any client needs to provide
070     * its own buffering.
071     *
072     * <pre>
073     * InputStream is = ...; // from http connection
074     * BurlapInput in = new BurlapInput(is);
075     * String value;
076     *
077     * in.startReply();         // read reply header
078     * value = in.readString(); // read string value
079     * in.completeReply();      // read reply footer
080     * </pre>
081     */
082    public class BurlapInput extends AbstractBurlapInput {
083      private static int []base64Decode;
084      
085      public final static int TAG_EOF = -1;
086      
087      public final static int TAG_NULL = 0;
088      public final static int TAG_BOOLEAN = 1;
089      public final static int TAG_INT = 2;
090      public final static int TAG_LONG = 3;
091      public final static int TAG_DOUBLE = 4;
092      public final static int TAG_DATE = 5;
093      public final static int TAG_STRING = 6;
094      public final static int TAG_XML = 7;
095      public final static int TAG_BASE64 = 8;
096      public final static int TAG_MAP = 9;
097      public final static int TAG_LIST = 10;
098      public final static int TAG_TYPE = 11;
099      public final static int TAG_LENGTH = 12;
100      
101      public final static int TAG_REF = 13;
102      public final static int TAG_REMOTE = 14;
103      
104      public final static int TAG_CALL = 15;
105      public final static int TAG_REPLY = 16;
106      public final static int TAG_FAULT = 17;
107      public final static int TAG_METHOD = 18;
108      public final static int TAG_HEADER = 19;
109      
110      public final static int TAG_NULL_END = TAG_NULL + 100;
111      public final static int TAG_BOOLEAN_END = TAG_BOOLEAN + 100;
112      public final static int TAG_INT_END = TAG_INT + 100;
113      public final static int TAG_LONG_END = TAG_LONG + 100;
114      public final static int TAG_DOUBLE_END = TAG_DOUBLE + 100;
115      public final static int TAG_DATE_END = TAG_DATE + 100;
116      public final static int TAG_STRING_END = TAG_STRING + 100;
117      public final static int TAG_XML_END = TAG_XML + 100;
118      public final static int TAG_BASE64_END = TAG_BASE64 + 100;
119      public final static int TAG_MAP_END = TAG_MAP + 100;
120      public final static int TAG_LIST_END = TAG_LIST + 100;
121      public final static int TAG_TYPE_END = TAG_TYPE + 100;
122      public final static int TAG_LENGTH_END = TAG_LENGTH + 100;
123      
124      public final static int TAG_REF_END = TAG_REF + 100;
125      public final static int TAG_REMOTE_END = TAG_REMOTE + 100;
126      
127      public final static int TAG_CALL_END = TAG_CALL + 100;
128      public final static int TAG_REPLY_END = TAG_REPLY + 100;
129      public final static int TAG_FAULT_END = TAG_FAULT + 100;
130      public final static int TAG_METHOD_END = TAG_METHOD + 100;
131      public final static int TAG_HEADER_END = TAG_HEADER + 100;
132    
133      private static HashMap _tagMap;
134    
135      private static Field _detailMessageField;
136      
137      protected SerializerFactory _serializerFactory;
138      
139      protected ArrayList _refs;
140      
141      // the underlying input stream
142      private InputStream _is;
143      // a peek character
144      protected int _peek = -1;
145      
146      // the method for a call
147      private String _method;
148    
149      private int _peekTag;
150    
151      private Throwable _replyFault;
152    
153      protected StringBuffer _sbuf = new StringBuffer();
154      protected StringBuffer _entityBuffer = new StringBuffer();
155      
156      protected Calendar _utcCalendar;
157      protected Calendar _localCalendar;
158    
159      /**
160       * Creates an uninitialized Burlap input stream.
161       */
162      public BurlapInput()
163      {
164      }
165      
166      /**
167       * Creates a new Burlap input stream, initialized with an
168       * underlying input stream.
169       *
170       * @param is the underlying input stream.
171       */
172      public BurlapInput(InputStream is)
173      {
174        init(is);
175      }
176    
177      /**
178       * Sets the serializer factory.
179       */
180      public void setSerializerFactory(SerializerFactory factory)
181      {
182        _serializerFactory = factory;
183      }
184    
185      /**
186       * Gets the serializer factory.
187       */
188      public SerializerFactory getSerializerFactory()
189      {
190        return _serializerFactory;
191      }
192    
193      /**
194       * Initialize the burlap stream with the underlying input stream.
195       */
196      public void init(InputStream is)
197      {
198        _is = is;
199        _method = null;
200        _peek = -1;
201        _peekTag = -1;
202        _refs = null;
203        _replyFault = null;
204    
205        if (_serializerFactory == null)
206          _serializerFactory = new SerializerFactory();
207      }
208    
209      /**
210       * Returns the calls method
211       */
212      public String getMethod()
213      {
214        return _method;
215      }
216    
217      /**
218       * Returns any reply fault.
219       */
220      public Throwable getReplyFault()
221      {
222        return _replyFault;
223      }
224    
225      /**
226       * Starts reading the call
227       *
228       * <pre>
229       * &lt;burlap:call>
230       * &lt;method>method&lt;/method>
231       * </pre>
232       */
233      public void startCall()
234        throws IOException
235      {
236        readCall();
237    
238        while ((readHeader() != null))
239          readObject();
240    
241        readMethod();
242      }
243    
244      /**
245       * Starts reading the call
246       *
247       * <p>A successful completion will have a single value:
248       *
249       * <pre>
250       * &lt;burlap:call>
251       * </pre>
252       */
253      public int readCall()
254        throws IOException
255      {
256        expectTag(TAG_CALL);
257    
258        int major = 1;
259        int minor = 0;
260    
261        return (major << 16) + minor;
262      }
263    
264      /**
265       * Reads the method
266       *
267       * <pre>
268       * &lt;method>method&lt;/method>
269       * </pre>
270       */
271      public String readMethod()
272        throws IOException
273      {
274        expectTag(TAG_METHOD);
275    
276        _method = parseString();
277    
278        expectTag(TAG_METHOD_END);
279    
280        return _method;
281      }
282    
283      /**
284       * Completes reading the call
285       *
286       * <p>A successful completion will have a single value:
287       *
288       * <pre>
289       * &lt;/burlap:call>
290       * </pre>
291       */
292      public void completeCall()
293        throws IOException
294      {
295        expectTag(TAG_CALL_END);
296      }
297    
298      /**
299       * Reads a reply as an object.
300       * If the reply has a fault, throws the exception.
301       */
302      public Object readReply(Class expectedClass)
303        throws Throwable
304      {
305        expectTag(TAG_REPLY);
306    
307        int tag = parseTag();
308    
309        if (tag == TAG_FAULT)
310          throw prepareFault();
311        else {
312          _peekTag = tag;
313          Object value = readObject(expectedClass);
314    
315          expectTag(TAG_REPLY_END);
316          
317          return value;
318        }
319      }
320    
321      /**
322       * Starts reading the reply
323       *
324       * <p>A successful completion will have a single value:
325       *
326       * <pre>
327       * &lt;burlap:reply>
328       * &lt;value>
329       * </pre>
330       */
331      public void startReply()
332        throws Throwable
333      {
334        expectTag(TAG_REPLY);
335        
336        int tag = parseTag();
337        if (tag == TAG_FAULT)
338          throw prepareFault();
339        else
340          _peekTag = tag;
341      }
342    
343      /**
344       * Prepares the fault.
345       */
346      private Throwable prepareFault()
347        throws IOException
348      {
349        HashMap fault = readFault();
350    
351        Object detail = fault.get("detail");
352        String message = (String) fault.get("message");
353    
354        if (detail instanceof Throwable) {
355          _replyFault = (Throwable) detail;
356          
357          if (message != null && _detailMessageField != null) {
358            try {
359              _detailMessageField.set(_replyFault, message);
360            } catch (Throwable e) {
361            }
362          }
363    
364          return _replyFault;
365        }
366    
367        else {
368          String code = (String) fault.get("code");
369            
370          _replyFault = new BurlapServiceException(message, code, detail);
371    
372          return _replyFault;
373        }
374      }
375    
376      /**
377       * Completes reading the call
378       *
379       * <p>A successful completion will have a single value:
380       *
381       * <pre>
382       * &lt;/burlap:reply>
383       * </pre>
384       */
385      public void completeReply()
386        throws IOException
387      {
388        expectTag(TAG_REPLY_END);
389      }
390    
391      /**
392       * Reads a header, returning null if there are no headers.
393       *
394       * <pre>
395       * &lt;header>value&lt;/header>
396       * </pre>
397       */
398      public String readHeader()
399        throws IOException
400      {
401        int tag = parseTag();
402    
403        if (tag == TAG_HEADER) {
404          _sbuf.setLength(0);
405          String value = parseString(_sbuf).toString();
406          expectTag(TAG_HEADER_END);
407          return value;
408        }
409    
410        _peekTag = tag;
411    
412        return null;
413      }
414    
415      /**
416       * Reads a null
417       *
418       * <pre>
419       * &lt;null>&lt;/null>
420       * </pre>
421       */
422      public void readNull()
423        throws IOException
424      {
425        int tag = parseTag();
426    
427        switch (tag) {
428        case TAG_NULL:
429          expectTag(TAG_NULL_END);
430          return;
431          
432        default:
433          throw expectedTag("null", tag);
434        }
435      }
436    
437      /**
438       * Reads a boolean
439       *
440       * <pre>
441       * &lt;boolean>0&lt;/boolean>
442       * &lt;boolean>1&lt;/boolean>
443       * </pre>
444       */
445      public boolean readBoolean()
446        throws IOException
447      {
448        int tag = parseTag();
449    
450        boolean value;
451    
452        switch (tag) {
453        case TAG_NULL:
454          value = false;
455          expectTag(TAG_NULL_END);
456          return value;
457    
458        case TAG_BOOLEAN:
459          value = parseInt() != 0;
460          expectTag(TAG_BOOLEAN_END);
461          return value;
462          
463        case TAG_INT:
464          value = parseInt() != 0;
465          expectTag(TAG_INT_END);
466          return value;
467          
468        case TAG_LONG:
469          value = parseLong() != 0;
470          expectTag(TAG_LONG_END);
471          return value;
472          
473        case TAG_DOUBLE:
474          value = parseDouble() != 0;
475          expectTag(TAG_DOUBLE_END);
476          return value;
477          
478        default:
479          throw expectedTag("boolean", tag);
480        }
481      }
482    
483      /**
484       * Reads a byte
485       *
486       * <pre>
487       * &lt;int>value&lt;/int>
488       * </pre>
489       */
490      public byte readByte()
491        throws IOException
492      {
493        return (byte) readInt();
494      }
495    
496      /**
497       * Reads a short
498       *
499       * <pre>
500       * &lt;int>value&lt;/int>
501       * </pre>
502       */
503      public short readShort()
504        throws IOException
505      {
506        return (short) readInt();
507      }
508    
509      /**
510       * Reads an integer
511       *
512       * <pre>
513       * &lt;int>value&lt;/int>
514       * </pre>
515       */
516      public int readInt()
517        throws IOException
518      {
519        int tag = parseTag();
520    
521        int value;
522    
523        switch (tag) {
524        case TAG_NULL:
525          value = 0;
526          expectTag(TAG_NULL_END);
527          return value;
528          
529        case TAG_BOOLEAN:
530          value = parseInt();
531          expectTag(TAG_BOOLEAN_END);
532          return value;
533          
534        case TAG_INT:
535          value = parseInt();
536          expectTag(TAG_INT_END);
537          return value;
538          
539        case TAG_LONG:
540          value = (int) parseLong();
541          expectTag(TAG_LONG_END);
542          return value;
543          
544        case TAG_DOUBLE:
545          value = (int) parseDouble();
546          expectTag(TAG_DOUBLE_END);
547          return value;
548          
549        default:
550          throw expectedTag("int", tag);
551        }
552      }
553    
554      /**
555       * Reads a long
556       *
557       * <pre>
558       * &lt;long>value&lt;/long>
559       * </pre>
560       */
561      public long readLong()
562        throws IOException
563      {
564        int tag = parseTag();
565    
566        long value;
567    
568        switch (tag) {
569        case TAG_NULL:
570          value = 0;
571          expectTag(TAG_NULL_END);
572          return value;
573          
574        case TAG_BOOLEAN:
575          value = parseInt();
576          expectTag(TAG_BOOLEAN_END);
577          return value;
578          
579        case TAG_INT:
580          value = parseInt();
581          expectTag(TAG_INT_END);
582          return value;
583          
584        case TAG_LONG:
585          value = parseLong();
586          expectTag(TAG_LONG_END);
587          return value;
588          
589        case TAG_DOUBLE:
590          value = (long) parseDouble();
591          expectTag(TAG_DOUBLE_END);
592          return value;
593          
594        default:
595          throw expectedTag("long", tag);
596        }
597      }
598    
599      /**
600       * Reads a float
601       *
602       * <pre>
603       * &lt;double>value&lt;/double>
604       * </pre>
605       */
606      public float readFloat()
607        throws IOException
608      {
609        return (float) readDouble();
610      }
611    
612      /**
613       * Reads a double
614       *
615       * <pre>
616       * &lt;double>value&lt;/double>
617       * </pre>
618       */
619      public double readDouble()
620        throws IOException
621      {
622        int tag = parseTag();
623    
624        double value;
625    
626        switch (tag) {
627        case TAG_NULL:
628          value = 0;
629          expectTag(TAG_NULL_END);
630          return value;
631          
632        case TAG_BOOLEAN:
633          value = parseInt();
634          expectTag(TAG_BOOLEAN_END);
635          return value;
636          
637        case TAG_INT:
638          value = parseInt();
639          expectTag(TAG_INT_END);
640          return value;
641          
642        case TAG_LONG:
643          value = parseLong();
644          expectTag(TAG_LONG_END);
645          return value;
646          
647        case TAG_DOUBLE:
648          value = parseDouble();
649          expectTag(TAG_DOUBLE_END);
650          return value;
651          
652        default:
653          throw expectedTag("double", tag);
654        }
655      }
656    
657      /**
658       * Reads a date.
659       *
660       * <pre>
661       * &lt;date>ISO-8609 date&lt;/date>
662       * </pre>
663       */
664      public long readUTCDate()
665        throws IOException
666      {
667        int tag = parseTag();
668    
669        if (tag != TAG_DATE)
670          throw error("expected date");
671    
672        if (_utcCalendar == null)
673          _utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
674    
675        long value = parseDate(_utcCalendar);
676    
677        expectTag(TAG_DATE_END);
678    
679        return value;
680      }
681    
682      /**
683       * Reads a date.
684       *
685       * <pre>
686       * &lt;date>ISO-8609 date&lt;/date>
687       * </pre>
688       */
689      public long readLocalDate()
690        throws IOException
691      {
692        int tag = parseTag();
693    
694        if (tag != TAG_DATE)
695          throw error("expected date");
696    
697        if (_localCalendar == null)
698          _localCalendar = Calendar.getInstance();
699    
700        long value = parseDate(_localCalendar);
701    
702        expectTag(TAG_DATE_END);
703    
704        return value;
705      }
706    
707      /**
708       * Reads a string
709       *
710       * <pre>
711       * &lt;string>value&lt;/string>
712       * </pre>
713       */
714      public String readString()
715        throws IOException
716      {
717        int tag = parseTag();
718    
719        String value;
720        
721        switch (tag) {
722        case TAG_NULL:
723          expectTag(TAG_NULL_END);
724          return null;
725    
726        case TAG_STRING:
727          _sbuf.setLength(0);
728          value = parseString(_sbuf).toString();
729          expectTag(TAG_STRING_END);
730          return value;
731    
732        case TAG_XML:
733          _sbuf.setLength(0);
734          value = parseString(_sbuf).toString();
735          expectTag(TAG_XML_END);
736          return value;
737    
738        default:
739          throw expectedTag("string", tag);
740        }
741      }
742    
743      /**
744       * Reads an XML node.
745       *
746       * <pre>
747       * &xml;xml string&lt;/xml>
748       * </pre>
749       */
750      public org.w3c.dom.Node readNode()
751        throws IOException
752      {
753        int tag = read();
754    
755        switch (tag) {
756        case 'N':
757          return null;
758    
759        case 'S':
760        case 's':
761        case 'X':
762        case 'x':
763          throw error("can't cope");
764    
765        default:
766          throw expectedTag("string", tag);
767        }
768      }
769    
770      /**
771       * Reads a byte array
772       *
773       * <pre>
774       * &lt;base64>...&lt;/base64>
775       * </pre>
776       */
777      public byte []readBytes()
778        throws IOException
779      {
780        int tag = parseTag();
781    
782        switch (tag) {
783        case TAG_NULL:
784          expectTag(TAG_NULL_END);
785          return null;
786    
787        case TAG_BASE64:
788          byte []data = parseBytes();
789          expectTag(TAG_BASE64_END);
790    
791          return data;
792          
793        default:
794          throw expectedTag("bytes", tag);
795        }
796      }
797    
798      /**
799       * Reads a length
800       *
801       * <pre>
802       * &lt;length>value&lt;/length>
803       * </pre>
804       */
805      public int readLength()
806        throws IOException
807      {
808        int tag = parseTag();
809    
810        if (tag != TAG_LENGTH) {
811          _peekTag = tag;
812          return -1;
813        }
814    
815        int value = parseInt();
816    
817        expectTag(TAG_LENGTH_END);
818    
819        return value;
820      }
821    
822      /**
823       * Reads a fault.
824       */
825      private HashMap readFault()
826        throws IOException
827      {
828        HashMap map = new HashMap();
829    
830        int code = parseTag();
831        for (; code >= 0 && code != TAG_FAULT_END; code = parseTag()) {
832          _peekTag = code;
833          
834          Object key = readObject();
835          Object value = readObject();
836    
837          if (key != null && value != null)
838            map.put(key, value);
839        }
840    
841        if (code != TAG_FAULT_END)
842          throw expectedTag("fault", code);
843    
844        return map;
845      }
846    
847      /**
848       * Reads an object from the input stream with an expected type.
849       */
850      public Object readObject(Class cl)
851        throws IOException
852      {
853        if (cl == null || cl.equals(Object.class))
854          return readObject();
855        
856        int tag = parseTag();
857    
858        switch (tag) {
859        case TAG_NULL:
860          expectTag(TAG_NULL_END);
861          return null;
862    
863        case TAG_MAP:
864        {
865          String type = readType();
866          Deserializer reader;
867          
868          reader = _serializerFactory.getObjectDeserializer(type, cl);
869    
870          return reader.readMap(this);
871        }
872    
873        case TAG_LIST:
874        {
875          String type = readType();
876          int length = readLength();
877          
878          Deserializer reader;
879          reader = _serializerFactory.getObjectDeserializer(type, cl);
880    
881          return reader.readList(this, length);
882        }
883    
884        case TAG_REF:
885        {
886          int ref = parseInt();
887    
888          expectTag(TAG_REF_END);
889    
890          return _refs.get(ref);
891        }
892    
893        case TAG_REMOTE:
894        {
895          String type = readType();
896          String url = readString();
897    
898          expectTag(TAG_REMOTE_END);
899    
900          Object remote = resolveRemote(type, url);
901          
902          return remote;
903        }
904        }
905        
906        _peekTag = tag;
907    
908        Object value = _serializerFactory.getDeserializer(cl).readObject(this);
909    
910        return value;
911      }
912      
913      /**
914       * Reads an arbitrary object from the input stream when the type
915       * is unknown.
916       */
917      public Object readObject()
918        throws IOException
919      {
920        int tag = parseTag();
921    
922        switch (tag) {
923        case TAG_NULL:
924          expectTag(TAG_NULL_END);
925          return null;
926          
927        case TAG_BOOLEAN:
928        {
929          int value = parseInt();
930          expectTag(TAG_BOOLEAN_END);
931          return new Boolean(value != 0);
932        }
933        
934        case TAG_INT:
935        {
936          int value = parseInt();
937          expectTag(TAG_INT_END);
938          return new Integer(value);
939        }
940        
941        case TAG_LONG:
942        {
943          long value = parseLong();
944          expectTag(TAG_LONG_END);
945          return new Long(value);
946        }
947        
948        case TAG_DOUBLE:
949        {
950          double value = parseDouble();
951          expectTag(TAG_DOUBLE_END);
952          return new Double(value);
953        }
954        
955        case TAG_DATE:
956        {
957          long value = parseDate();
958          expectTag(TAG_DATE_END);
959          return new Date(value);
960        }
961        
962        case TAG_XML:
963        {
964          return parseXML();
965        }
966    
967        case TAG_STRING:
968        {
969          _sbuf.setLength(0);
970    
971          String value = parseString(_sbuf).toString();
972    
973          expectTag(TAG_STRING_END);
974    
975          return value;
976        }
977    
978        case TAG_BASE64:
979        {
980          byte []data = parseBytes();
981    
982          expectTag(TAG_BASE64_END);
983    
984          return data;
985        }
986    
987        case TAG_LIST:
988        {
989          String type = readType();
990          int length = readLength();
991    
992          return _serializerFactory.readList(this, length, type);
993        }
994    
995        case TAG_MAP:
996        {
997          String type = readType();
998          Deserializer deserializer;
999          deserializer = _serializerFactory.getObjectDeserializer(type);
1000    
1001          return deserializer.readMap(this);
1002        }
1003    
1004        case TAG_REF:
1005        {
1006          int ref = parseInt();
1007    
1008          expectTag(TAG_REF_END);
1009    
1010          return _refs.get(ref);
1011        }
1012    
1013        case TAG_REMOTE:
1014        {
1015          String type = readType();
1016          String url = readString();
1017    
1018          expectTag(TAG_REMOTE_END);
1019    
1020          return resolveRemote(type, url);
1021        }
1022    
1023        default:
1024          throw error("unknown code:" + tagName(tag));
1025        }
1026      }
1027    
1028      /**
1029       * Reads a remote object.
1030       */
1031      public Object readRemote()
1032        throws IOException
1033      {
1034        String type = readType();
1035        String url = readString();
1036    
1037        return resolveRemote(type, url);
1038      }
1039    
1040      /**
1041       * Reads a reference.
1042       */
1043      public Object readRef()
1044        throws IOException
1045      {
1046        return _refs.get(parseInt());
1047      }
1048    
1049      /**
1050       * Reads the start of a list.
1051       */
1052      public int readListStart()
1053        throws IOException
1054      {
1055        return parseTag();
1056      }
1057    
1058      /**
1059       * Reads the start of a map.
1060       */
1061      public int readMapStart()
1062        throws IOException
1063      {
1064        return parseTag();
1065      }
1066    
1067      /**
1068       * Returns true if this is the end of a list or a map.
1069       */
1070      public boolean isEnd()
1071        throws IOException
1072      {
1073        int code = parseTag();
1074    
1075        _peekTag = code;
1076    
1077        return (code < 0 || code >= 100);
1078      }
1079    
1080      /**
1081       * Reads the end byte.
1082       */
1083      public void readEnd()
1084        throws IOException
1085      {
1086        int code = parseTag();
1087    
1088        if (code < 100)
1089          throw error("unknown code:" + (char) code);
1090      }
1091    
1092      /**
1093       * Reads the end of the map
1094       */
1095      public void readMapEnd()
1096        throws IOException
1097      {
1098        expectTag(TAG_MAP_END);
1099      }
1100    
1101      /**
1102       * Reads the end of the map
1103       */
1104      public void readListEnd()
1105        throws IOException
1106      {
1107        expectTag(TAG_LIST_END);
1108      }
1109    
1110      /**
1111       * Adds a list/map reference.
1112       */
1113      public int addRef(Object ref)
1114      {
1115        if (_refs == null)
1116          _refs = new ArrayList();
1117        
1118        _refs.add(ref);
1119    
1120        return _refs.size() - 1;
1121      }
1122    
1123      /**
1124       * Adds a list/map reference.
1125       */
1126      public void setRef(int i, Object ref)
1127      {
1128        _refs.set(i, ref);
1129      }
1130    
1131      /**
1132       * Resolves a remote object.
1133       */
1134      public Object resolveRemote(String type, String url)
1135        throws IOException
1136      {
1137        HessianRemoteResolver resolver = getRemoteResolver();
1138    
1139        if (resolver != null)
1140          return resolver.lookup(type, url);
1141        else
1142          return new BurlapRemote(type, url);
1143      }
1144    
1145      /**
1146       * Parses a type from the stream.
1147       *
1148       * <pre>
1149       * &lt;type>type&lt;/type>
1150       * </pre>
1151       */
1152      public String readType()
1153        throws IOException
1154      {
1155        int code = parseTag();
1156    
1157        if (code != TAG_TYPE) {
1158          _peekTag = code;
1159          return "";
1160        }
1161    
1162        _sbuf.setLength(0);
1163        int ch;
1164        while ((ch = readChar()) >= 0)
1165          _sbuf.append((char) ch);
1166        String type = _sbuf.toString();
1167        
1168        expectTag(TAG_TYPE_END);
1169    
1170        return type;
1171      }
1172    
1173      /**
1174       * Parses a 32-bit integer value from the stream.
1175       */
1176      private int parseInt()
1177        throws IOException
1178      {
1179        int sign = 1;
1180    
1181        int ch = read();
1182        if (ch == '-') {
1183          sign = -1;
1184          ch = read();
1185        }
1186    
1187        int value = 0;
1188        for (; ch >= '0' && ch <= '9'; ch = read())
1189          value = 10 * value + ch - '0';
1190    
1191        _peek = ch;
1192    
1193        return sign * value;
1194      }
1195    
1196      /**
1197       * Parses a 64-bit long value from the stream.
1198       */
1199      private long parseLong()
1200        throws IOException
1201      {
1202        int sign = 1;
1203    
1204        int ch = read();
1205        if (ch == '-') {
1206          sign = -1;
1207          ch = read();
1208        }
1209    
1210        long value = 0;
1211        for (; ch >= '0' && ch <= '9'; ch = read())
1212          value = 10 * value + ch - '0';
1213    
1214        _peek = ch;
1215    
1216        return sign * value;
1217      }
1218      
1219      /**
1220       * Parses a 64-bit double value from the stream.
1221       *
1222       * <pre>
1223       * b64 b56 b48 b40 b32 b24 b16 b8
1224       * </pre>
1225       */
1226      private double parseDouble()
1227        throws IOException
1228      {
1229        int ch = skipWhitespace();
1230    
1231        _sbuf.setLength(0);
1232        
1233        for (; ! isWhitespace(ch) && ch != '<'; ch = read())
1234          _sbuf.append((char) ch);
1235    
1236        _peek = ch;
1237        
1238        return new Double(_sbuf.toString()).doubleValue();
1239      }
1240    
1241      /**
1242       * Parses a date value from the stream.
1243       */
1244      protected long parseDate()
1245        throws IOException
1246      {
1247        if (_utcCalendar == null)
1248          _utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
1249    
1250        return parseDate(_utcCalendar);
1251      }
1252    
1253      /**
1254       * Parses a date value from the stream.
1255       */
1256      protected long parseDate(Calendar calendar)
1257        throws IOException
1258      {
1259        int ch = skipWhitespace();
1260        
1261        int year = 0;
1262        for (int i = 0; i < 4; i++) {
1263          if (ch >= '0' && ch <= '9')
1264            year = 10 * year + ch - '0';
1265          else
1266            throw expectedChar("year", ch);
1267    
1268          ch = read();
1269        }
1270    
1271        int month = 0;
1272        for (int i = 0; i < 2; i++) {
1273          if (ch >= '0' && ch <= '9')
1274            month = 10 * month + ch - '0';
1275          else
1276            throw expectedChar("month", ch);
1277    
1278          ch = read();
1279        }
1280    
1281        int day = 0;
1282        for (int i = 0; i < 2; i++) {
1283          if (ch >= '0' && ch <= '9')
1284            day = 10 * day + ch - '0';
1285          else
1286            throw expectedChar("day", ch);
1287    
1288          ch = read();
1289        }
1290    
1291        if (ch != 'T')
1292          throw expectedChar("`T'", ch);
1293    
1294        ch = read();
1295    
1296        int hour = 0;
1297        for (int i = 0; i < 2; i++) {
1298          if (ch >= '0' && ch <= '9')
1299            hour = 10 * hour + ch - '0';
1300          else
1301            throw expectedChar("hour", ch);
1302    
1303          ch = read();
1304        }
1305    
1306        int minute = 0;
1307        for (int i = 0; i < 2; i++) {
1308          if (ch >= '0' && ch <= '9')
1309            minute = 10 * minute + ch - '0';
1310          else
1311            throw expectedChar("minute", ch);
1312    
1313          ch = read();
1314        }
1315    
1316        int second = 0;
1317        for (int i = 0; i < 2; i++) {
1318          if (ch >= '0' && ch <= '9')
1319            second = 10 * second + ch - '0';
1320          else
1321            throw expectedChar("second", ch);
1322    
1323          ch = read();
1324        }
1325    
1326        int ms = 0;
1327        if (ch == '.') {
1328          ch = read();
1329    
1330          while (ch >= '0' && ch <= '9') {
1331            ms = 10 * ms + ch - '0';
1332    
1333            ch = read();
1334          }
1335        }
1336    
1337        for (; ch > 0 && ch != '<'; ch = read()) {
1338        }
1339    
1340        _peek = ch;
1341    
1342        calendar.set(Calendar.YEAR, year);
1343        calendar.set(Calendar.MONTH, month - 1);
1344        calendar.set(Calendar.DAY_OF_MONTH, day);
1345        calendar.set(Calendar.HOUR_OF_DAY, hour);
1346        calendar.set(Calendar.MINUTE, minute);
1347        calendar.set(Calendar.SECOND, second);
1348        calendar.set(Calendar.MILLISECOND, ms);
1349    
1350        return calendar.getTime().getTime();
1351      }
1352      
1353      protected String parseString()
1354        throws IOException
1355      {
1356        _sbuf.setLength(0);
1357    
1358        return parseString(_sbuf).toString();
1359      }
1360      
1361      /**
1362       * Parses a string value from the stream.  The burlap object's
1363       * string buffer is used for the result.
1364       */
1365      protected StringBuffer parseString(StringBuffer sbuf)
1366        throws IOException
1367      {
1368        int ch;
1369    
1370        while ((ch = readChar()) >= 0)
1371          sbuf.append((char) ch);
1372    
1373        return sbuf;
1374      }
1375    
1376      org.w3c.dom.Node parseXML()
1377        throws IOException
1378      {
1379        throw error("help!");
1380      }
1381      
1382      /**
1383       * Reads a character from the underlying stream.
1384       */
1385      int readChar()
1386        throws IOException
1387      {
1388        int ch = read();
1389    
1390        if (ch == '<' || ch < 0) {
1391          _peek = ch;
1392          return -1;
1393        }
1394        
1395        if (ch == '&') {
1396          ch = read();
1397    
1398          if (ch == '#') {
1399            ch = read();
1400    
1401            if (ch >= '0' && ch <= '9') {
1402              int v = 0;
1403              for (; ch >= '0' && ch <= '9'; ch = read()) {
1404                v = 10 * v + ch - '0';
1405              }
1406    
1407              if (ch != ';')
1408                throw error("expected ';' at " + (char) ch);
1409    
1410              return (char) v;
1411            }
1412            else
1413              throw error("expected digit at " + (char) ch);
1414          }
1415          else {
1416            _entityBuffer.setLength(0);
1417    
1418            for (; ch >= 'a' && ch <= 'z'; ch = read())
1419              _entityBuffer.append((char) ch);
1420    
1421            String entity = _entityBuffer.toString();
1422    
1423            if (ch != ';')
1424              throw expectedChar("';'", ch);
1425            
1426            if (entity.equals("amp"))
1427              return '&';
1428            else if (entity.equals("apos"))
1429              return '\'';
1430            else if (entity.equals("quot"))
1431              return '"';
1432            else if (entity.equals("lt"))
1433              return '<';
1434            else if (entity.equals("gt"))
1435              return '>';
1436            else
1437              throw new BurlapProtocolException("unknown XML entity &" + entity + "; at `" + (char) ch + "'");
1438          }
1439        }
1440        else if (ch < 0x80)
1441          return (char) ch;
1442        else if ((ch & 0xe0) == 0xc0) {
1443          int ch1 = read();
1444          int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
1445    
1446          return (char) v;
1447        }
1448        else if ((ch & 0xf0) == 0xe0) {
1449          int ch1 = read();
1450          int ch2 = read();
1451          int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f);
1452    
1453          return (char) v;
1454        }
1455        else
1456          throw new BurlapProtocolException("bad utf-8 encoding");
1457      }
1458      
1459      /**
1460       * Parses a byte array.
1461       */
1462      protected byte []parseBytes()
1463        throws IOException
1464      {
1465        ByteArrayOutputStream bos = new ByteArrayOutputStream();
1466    
1467        parseBytes(bos);
1468    
1469        return bos.toByteArray();
1470      }
1471      
1472      /**
1473       * Parses a byte array.
1474       */
1475      protected ByteArrayOutputStream parseBytes(ByteArrayOutputStream bos)
1476        throws IOException
1477      {
1478        int ch;
1479        for (ch = skipWhitespace(); ch >= 0 && ch != '<'; ch = skipWhitespace()) {
1480          int b1 = ch;
1481          int b2 = read();
1482          int b3 = read();
1483          int b4 = read();
1484    
1485          if (b4 != '=') {
1486            int chunk = ((base64Decode[b1] << 18) +
1487                         (base64Decode[b2] << 12) +
1488                         (base64Decode[b3] << 6) +
1489                         (base64Decode[b4]));
1490    
1491            bos.write(chunk >> 16);
1492            bos.write(chunk >> 8);
1493            bos.write(chunk);
1494          }
1495          else if (b3 != '=') {
1496            int chunk = ((base64Decode[b1] << 10) +
1497                         (base64Decode[b2] << 4) +
1498                         (base64Decode[b3] >> 2));
1499    
1500            bos.write(chunk >> 8);
1501            bos.write(chunk);
1502          }
1503          else {
1504            int chunk = ((base64Decode[b1] << 2) +
1505                         (base64Decode[b2] >> 4));
1506    
1507            bos.write(chunk);
1508          }
1509        }
1510    
1511        if (ch == '<')
1512          _peek = ch;
1513        
1514        return bos;
1515      }
1516      
1517      public void expectTag(int expectTag)
1518        throws IOException
1519      {
1520        int tag = parseTag();
1521    
1522        if (tag != expectTag)
1523          throw error("expected " + tagName(expectTag) + " at " + tagName(tag));
1524      }
1525    
1526      /**
1527       * Parses a tag.  Returns true if it's a start tag.
1528       */
1529      protected int parseTag()
1530        throws IOException
1531      {
1532        if (_peekTag >= 0) {
1533          int tag = _peekTag;
1534          _peekTag = -1;
1535          return tag;
1536        }
1537        
1538        int ch = skipWhitespace();
1539        int endTagDelta = 0;
1540    
1541        if (ch != '<')
1542          throw expectedChar("'<'", ch);
1543    
1544        ch = read();
1545        if (ch == '/') {
1546          endTagDelta = 100;
1547          ch = _is.read();
1548        }
1549        
1550        if (! isTagChar(ch))
1551          throw expectedChar("tag", ch);
1552          
1553        _sbuf.setLength(0);
1554        for (; isTagChar(ch); ch = read())
1555          _sbuf.append((char) ch);
1556    
1557        if (ch != '>')
1558          throw expectedChar("'>'", ch);
1559    
1560        Integer value = (Integer) _tagMap.get(_sbuf.toString());
1561        if (value == null)
1562          throw error("Unknown tag <" + _sbuf + ">");
1563    
1564        return value.intValue() + endTagDelta;
1565      }
1566    
1567      /**
1568       * Returns true if the character is a valid tag character.
1569       */
1570      private boolean isTagChar(int ch)
1571      {
1572        return (ch >= 'a' && ch <= 'z' ||
1573                ch >= 'A' && ch <= 'Z' ||
1574                ch >= '0' && ch <= '9' ||
1575                ch == ':' || ch == '-');
1576      }
1577    
1578      protected int skipWhitespace()
1579        throws IOException
1580      {
1581        int ch = read();
1582    
1583        for (;
1584             ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
1585             ch = read()) {
1586        }
1587    
1588        return ch;
1589      }
1590    
1591      protected boolean isWhitespace(int ch)
1592        throws IOException
1593      {
1594        return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
1595      }
1596      
1597      /**
1598       * Reads bytes from the underlying stream.
1599       */
1600      int read(byte []buffer, int offset, int length)
1601        throws IOException
1602      {
1603        throw new UnsupportedOperationException();
1604      }
1605    
1606      int read()
1607        throws IOException
1608      {
1609        if (_peek >= 0) {
1610          int value = _peek;
1611          _peek = -1;
1612          return value;
1613        }
1614    
1615        int ch = _is.read();
1616        return ch;
1617      }
1618    
1619      public Reader getReader()
1620      {
1621        return null;
1622      }
1623    
1624      public InputStream readInputStream()
1625      {
1626        return null;
1627      }
1628    
1629      public InputStream getInputStream()
1630      {
1631        return null;
1632      }
1633    
1634      protected IOException expectBeginTag(String expect, String tag)
1635      {
1636        return new BurlapProtocolException("expected <" + expect + "> at <" + tag + ">");
1637      }
1638      
1639      protected IOException expectedChar(String expect, int ch)
1640      {
1641        if (ch < 0)
1642          return error("expected " + expect + " at end of file");
1643        else
1644          return error("expected " + expect + " at " + (char) ch);
1645      }
1646      
1647      protected IOException expectedTag(String expect, int tag)
1648      {
1649        return error("expected " + expect + " at " + tagName(tag));
1650      }
1651      
1652      protected IOException error(String message)
1653      {
1654        return new BurlapProtocolException(message);
1655      }
1656    
1657      protected static String tagName(int tag)
1658      {
1659        switch (tag) {
1660        case TAG_NULL:
1661          return "<null>";
1662        case TAG_NULL_END:
1663          return "</null>";
1664          
1665        case TAG_BOOLEAN:
1666          return "<boolean>";
1667        case TAG_BOOLEAN_END:
1668          return "</boolean>";
1669          
1670        case TAG_INT:
1671          return "<int>";
1672        case TAG_INT_END:
1673          return "</int>";
1674          
1675        case TAG_LONG:
1676          return "<long>";
1677        case TAG_LONG_END:
1678          return "</long>";
1679          
1680        case TAG_DOUBLE:
1681          return "<double>";
1682        case TAG_DOUBLE_END:
1683          return "</double>";
1684          
1685        case TAG_STRING:
1686          return "<string>";
1687        case TAG_STRING_END:
1688          return "</string>";
1689          
1690        case TAG_XML:
1691          return "<xml>";
1692        case TAG_XML_END:
1693          return "</xml>";
1694          
1695        case TAG_BASE64:
1696          return "<base64>";
1697        case TAG_BASE64_END:
1698          return "</base64>";
1699          
1700        case TAG_MAP:
1701          return "<map>";
1702        case TAG_MAP_END:
1703          return "</map>";
1704          
1705        case TAG_LIST:
1706          return "<list>";
1707        case TAG_LIST_END:
1708          return "</list>";
1709          
1710        case TAG_TYPE:
1711          return "<type>";
1712        case TAG_TYPE_END:
1713          return "</type>";
1714          
1715        case TAG_LENGTH:
1716          return "<length>";
1717        case TAG_LENGTH_END:
1718          return "</length>";
1719          
1720        case TAG_REF:
1721          return "<ref>";
1722        case TAG_REF_END:
1723          return "</ref>";
1724          
1725        case TAG_REMOTE:
1726          return "<remote>";
1727        case TAG_REMOTE_END:
1728          return "</remote>";
1729          
1730        case TAG_CALL:
1731          return "<burlap:call>";
1732        case TAG_CALL_END:
1733          return "</burlap:call>";
1734          
1735        case TAG_REPLY:
1736          return "<burlap:reply>";
1737        case TAG_REPLY_END:
1738          return "</burlap:reply>";
1739          
1740        case TAG_HEADER:
1741          return "<header>";
1742        case TAG_HEADER_END:
1743          return "</header>";
1744          
1745        case TAG_FAULT:
1746          return "<fault>";
1747        case TAG_FAULT_END:
1748          return "</fault>";
1749    
1750        case -1:
1751          return "end of file";
1752    
1753        default:
1754          return "unknown " + tag;
1755        }
1756      }
1757          
1758    
1759      static {
1760        _tagMap = new HashMap();
1761        _tagMap.put("null", new Integer(TAG_NULL));
1762        
1763        _tagMap.put("boolean", new Integer(TAG_BOOLEAN));
1764        _tagMap.put("int", new Integer(TAG_INT));
1765        _tagMap.put("long", new Integer(TAG_LONG));
1766        _tagMap.put("double", new Integer(TAG_DOUBLE));
1767        
1768        _tagMap.put("date", new Integer(TAG_DATE));
1769        
1770        _tagMap.put("string", new Integer(TAG_STRING));
1771        _tagMap.put("xml", new Integer(TAG_XML));
1772        _tagMap.put("base64", new Integer(TAG_BASE64));
1773        
1774        _tagMap.put("map", new Integer(TAG_MAP));
1775        _tagMap.put("list", new Integer(TAG_LIST));
1776        
1777        _tagMap.put("type", new Integer(TAG_TYPE));
1778        _tagMap.put("length", new Integer(TAG_LENGTH));
1779        
1780        _tagMap.put("ref", new Integer(TAG_REF));
1781        _tagMap.put("remote", new Integer(TAG_REMOTE));
1782        
1783        _tagMap.put("burlap:call", new Integer(TAG_CALL));
1784        _tagMap.put("burlap:reply", new Integer(TAG_REPLY));
1785        _tagMap.put("fault", new Integer(TAG_FAULT));
1786        _tagMap.put("method", new Integer(TAG_METHOD));
1787        _tagMap.put("header", new Integer(TAG_HEADER));
1788      }
1789      
1790      static {
1791        base64Decode = new int[256];
1792        for (int i = 'A'; i <= 'Z'; i++)
1793          base64Decode[i] = i - 'A';
1794        for (int i = 'a'; i <= 'z'; i++)
1795          base64Decode[i] = i - 'a' + 26;
1796        for (int i = '0'; i <= '9'; i++)
1797          base64Decode[i] = i - '0' + 52;
1798        base64Decode['+'] = 62;
1799        base64Decode['/'] = 63;
1800      }
1801    
1802      static {
1803        try {
1804          _detailMessageField = Throwable.class.getDeclaredField("detailMessage");
1805          _detailMessageField.setAccessible(true);
1806        } catch (Throwable e) {
1807        }
1808      }
1809    }