KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > hessian > io > HessianInput


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 "Hessian", "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.hessian.io;
50
51 import java.io.ByteArrayOutputStream JavaDoc;
52 import java.io.IOException JavaDoc;
53 import java.io.InputStream JavaDoc;
54 import java.io.Reader JavaDoc;
55 import java.lang.reflect.Field JavaDoc;
56 import java.util.ArrayList JavaDoc;
57 import java.util.Date JavaDoc;
58 import java.util.HashMap JavaDoc;
59
60 /**
61  * Input stream for Hessian requests.
62  *
63  * <p>HessianInput is unbuffered, so any client needs to provide
64  * its own buffering.
65  *
66  * <pre>
67  * InputStream is = ...; // from http connection
68  * HessianInput in = new HessianInput(is);
69  * String value;
70  *
71  * in.startReply(); // read reply header
72  * value = in.readString(); // read string value
73  * in.completeReply(); // read reply footer
74  * </pre>
75  */

76 public class HessianInput extends AbstractHessianInput {
77   private static int END_OF_DATA = -2;
78
79   private static Field JavaDoc _detailMessageField;
80   
81   // factory for deserializing objects in the input stream
82
protected SerializerFactory _serializerFactory;
83   
84   protected ArrayList JavaDoc _refs;
85   
86   // the underlying input stream
87
private InputStream JavaDoc _is;
88   // a peek character
89
protected int _peek = -1;
90   
91   // the method for a call
92
private String JavaDoc _method;
93
94   private Reader JavaDoc _chunkReader;
95   private InputStream JavaDoc _chunkInputStream;
96
97   private Throwable JavaDoc _replyFault;
98
99   private StringBuffer JavaDoc _sbuf = new StringBuffer JavaDoc();
100   
101   // true if this is the last chunk
102
private boolean _isLastChunk;
103   // the chunk length
104
private int _chunkLength;
105
106   /**
107    * Creates an uninitialized Hessian input stream.
108    */

109   public HessianInput()
110   {
111   }
112   
113   /**
114    * Creates a new Hessian input stream, initialized with an
115    * underlying input stream.
116    *
117    * @param is the underlying input stream.
118    */

119   public HessianInput(InputStream JavaDoc is)
120   {
121     init(is);
122   }
123
124   /**
125    * Sets the serializer factory.
126    */

127   public void setSerializerFactory(SerializerFactory factory)
128   {
129     _serializerFactory = factory;
130   }
131
132   /**
133    * Gets the serializer factory.
134    */

135   public SerializerFactory getSerializerFactory()
136   {
137     return _serializerFactory;
138   }
139
140   /**
141    * Initialize the hessian stream with the underlying input stream.
142    */

143   public void init(InputStream JavaDoc is)
144   {
145     _is = is;
146     _method = null;
147     _isLastChunk = true;
148     _chunkLength = 0;
149     _peek = -1;
150     _refs = null;
151     _replyFault = null;
152
153     if (_serializerFactory == null)
154       _serializerFactory = new SerializerFactory();
155   }
156
157   /**
158    * Returns the calls method
159    */

160   public String JavaDoc getMethod()
161   {
162     return _method;
163   }
164
165   /**
166    * Returns any reply fault.
167    */

168   public Throwable JavaDoc getReplyFault()
169   {
170     return _replyFault;
171   }
172
173   /**
174    * Starts reading the call
175    *
176    * <pre>
177    * c major minor
178    * </pre>
179    */

180   public int readCall()
181     throws IOException JavaDoc
182   {
183     int tag = read();
184     
185     if (tag != 'c')
186       throw error("expected hessian call ('c') at code=" + tag + " ch=" + (char) tag);
187
188     int major = read();
189     int minor = read();
190
191     return (major << 16) + minor;
192   }
193
194   /**
195    * Starts reading the call
196    *
197    * <p>A successful completion will have a single value:
198    *
199    * <pre>
200    * m b16 b8 method
201    * </pre>
202    */

203   public String JavaDoc readMethod()
204     throws IOException JavaDoc
205   {
206     int tag = read();
207     
208     if (tag != 'm')
209       throw error("expected hessian method ('m') at code=" + tag + " ch=" + (char) tag);
210     int d1 = read();
211     int d2 = read();
212
213     _isLastChunk = true;
214     _chunkLength = d1 * 256 + d2;
215     _sbuf.setLength(0);
216     int ch;
217     while ((ch = parseChar()) >= 0)
218       _sbuf.append((char) ch);
219     
220     _method = _sbuf.toString();
221
222     return _method;
223   }
224
225   /**
226    * Starts reading the call, including the headers.
227    *
228    * <p>The call expects the following protocol data
229    *
230    * <pre>
231    * c major minor
232    * m b16 b8 method
233    * </pre>
234    */

235   public void startCall()
236     throws IOException JavaDoc
237   {
238     readCall();
239
240     while (readHeader() != null) {
241       readObject();
242     }
243
244     readMethod();
245   }
246
247   /**
248    * Completes reading the call
249    *
250    * <p>A successful completion will have a single value:
251    *
252    * <pre>
253    * z
254    * </pre>
255    */

256   public void completeCall()
257     throws IOException JavaDoc
258   {
259     int tag = read();
260
261     if (tag == 'z') {
262     }
263     else if (tag < 0)
264       throw error("expected end of call ('z') at end of stream.");
265     else
266       throw error("expected end of call ('z') at '" + (char) tag + "'. Check method arguments and ensure method overloading is enabled if necessary");
267   }
268
269   /**
270    * Reads a reply as an object.
271    * If the reply has a fault, throws the exception.
272    */

273   public Object JavaDoc readReply(Class JavaDoc expectedClass)
274     throws Throwable JavaDoc
275   {
276     int tag = read();
277     
278     if (tag != 'r')
279       error("expected hessian reply");
280
281     int major = read();
282     int minor = read();
283
284     tag = read();
285     if (tag == 'f')
286       throw prepareFault();
287     else {
288       _peek = tag;
289     
290       Object JavaDoc value = readObject(expectedClass);
291       
292       completeValueReply();
293       
294       return value;
295     }
296   }
297
298   /**
299    * Starts reading the reply
300    *
301    * <p>A successful completion will have a single value:
302    *
303    * <pre>
304    * r
305    * </pre>
306    */

307   public void startReply()
308     throws Throwable JavaDoc
309   {
310     int tag = read();
311     
312     if (tag != 'r')
313       error("expected hessian reply");
314
315     int major = read();
316     int minor = read();
317     
318     tag = read();
319     if (tag == 'f')
320       throw prepareFault();
321     else
322       _peek = tag;
323   }
324
325   /**
326    * Prepares the fault.
327    */

328   private Throwable JavaDoc prepareFault()
329     throws IOException JavaDoc
330   {
331     HashMap JavaDoc fault = readFault();
332
333     Object JavaDoc detail = fault.get("detail");
334     String JavaDoc message = (String JavaDoc) fault.get("message");
335
336     if (detail instanceof Throwable JavaDoc) {
337       _replyFault = (Throwable JavaDoc) detail;
338       
339       if (message != null && _detailMessageField != null) {
340     try {
341       _detailMessageField.set(_replyFault, message);
342     } catch (Throwable JavaDoc e) {
343     }
344       }
345     
346       return _replyFault;
347     }
348
349     else {
350       String JavaDoc code = (String JavaDoc) fault.get("code");
351         
352       _replyFault = new HessianServiceException(message, code, detail);
353
354       return _replyFault;
355     }
356   }
357
358   /**
359    * Completes reading the call
360    *
361    * <p>A successful completion will have a single value:
362    *
363    * <pre>
364    * z
365    * </pre>
366    */

367   public void completeReply()
368     throws IOException JavaDoc
369   {
370     int tag = read();
371     
372     if (tag != 'z')
373       error("expected end of reply");
374   }
375
376   /**
377    * Completes reading the call
378    *
379    * <p>A successful completion will have a single value:
380    *
381    * <pre>
382    * z
383    * </pre>
384    */

385   public void completeValueReply()
386     throws IOException JavaDoc
387   {
388     int tag = read();
389     
390     if (tag != 'z')
391       error("expected end of reply");
392   }
393
394   /**
395    * Reads a header, returning null if there are no headers.
396    *
397    * <pre>
398    * H b16 b8 value
399    * </pre>
400    */

401   public String JavaDoc readHeader()
402     throws IOException JavaDoc
403   {
404     int tag = read();
405
406     if (tag == 'H') {
407       _isLastChunk = true;
408       _chunkLength = (read() << 8) + read();
409
410       _sbuf.setLength(0);
411       int ch;
412       while ((ch = parseChar()) >= 0)
413         _sbuf.append((char) ch);
414
415       return _sbuf.toString();
416     }
417
418     _peek = tag;
419
420     return null;
421   }
422
423   /**
424    * Reads a null
425    *
426    * <pre>
427    * N
428    * </pre>
429    */

430   public void readNull()
431     throws IOException JavaDoc
432   {
433     int tag = read();
434
435     switch (tag) {
436     case 'N': return;
437       
438     default:
439       throw expect("null", tag);
440     }
441   }
442
443   /**
444    * Reads a boolean
445    *
446    * <pre>
447    * T
448    * F
449    * </pre>
450    */

451   public boolean readBoolean()
452     throws IOException JavaDoc
453   {
454     int tag = read();
455
456     switch (tag) {
457     case 'T': return true;
458     case 'F': return false;
459     case 'I': return parseInt() == 0;
460     case 'L': return parseLong() == 0;
461     case 'D': return parseDouble() == 0.0;
462     case 'N': return false;
463       
464     default:
465       throw expect("boolean", tag);
466     }
467   }
468
469   /**
470    * Reads a byte
471    *
472    * <pre>
473    * I b32 b24 b16 b8
474    * </pre>
475    */

476   /*
477   public byte readByte()
478     throws IOException
479   {
480     return (byte) readInt();
481   }
482   */

483
484   /**
485    * Reads a short
486    *
487    * <pre>
488    * I b32 b24 b16 b8
489    * </pre>
490    */

491   public short readShort()
492     throws IOException JavaDoc
493   {
494     return (short) readInt();
495   }
496
497   /**
498    * Reads an integer
499    *
500    * <pre>
501    * I b32 b24 b16 b8
502    * </pre>
503    */

504   public int readInt()
505     throws IOException JavaDoc
506   {
507     int tag = read();
508
509     switch (tag) {
510     case 'T': return 1;
511     case 'F': return 0;
512     case 'I': return parseInt();
513     case 'L': return (int) parseLong();
514     case 'D': return (int) parseDouble();
515       
516     default:
517       throw expect("int", tag);
518     }
519   }
520
521   /**
522    * Reads a long
523    *
524    * <pre>
525    * L b64 b56 b48 b40 b32 b24 b16 b8
526    * </pre>
527    */

528   public long readLong()
529     throws IOException JavaDoc
530   {
531     int tag = read();
532
533     switch (tag) {
534     case 'T': return 1;
535     case 'F': return 0;
536     case 'I': return parseInt();
537     case 'L': return parseLong();
538     case 'D': return (long) parseDouble();
539       
540     default:
541       throw expect("long", tag);
542     }
543   }
544
545   /**
546    * Reads a float
547    *
548    * <pre>
549    * D b64 b56 b48 b40 b32 b24 b16 b8
550    * </pre>
551    */

552   public float readFloat()
553     throws IOException JavaDoc
554   {
555     return (float) readDouble();
556   }
557
558   /**
559    * Reads a double
560    *
561    * <pre>
562    * D b64 b56 b48 b40 b32 b24 b16 b8
563    * </pre>
564    */

565   public double readDouble()
566     throws IOException JavaDoc
567   {
568     int tag = read();
569
570     switch (tag) {
571     case 'T': return 1;
572     case 'F': return 0;
573     case 'I': return parseInt();
574     case 'L': return (double) parseLong();
575     case 'D': return parseDouble();
576       
577     default:
578       throw expect("long", tag);
579     }
580   }
581
582   /**
583    * Reads a date.
584    *
585    * <pre>
586    * T b64 b56 b48 b40 b32 b24 b16 b8
587    * </pre>
588    */

589   public long readUTCDate()
590     throws IOException JavaDoc
591   {
592     int tag = read();
593
594     if (tag != 'd')
595       throw error("expected date");
596
597     long b64 = read();
598     long b56 = read();
599     long b48 = read();
600     long b40 = read();
601     long b32 = read();
602     long b24 = read();
603     long b16 = read();
604     long b8 = read();
605
606     return ((b64 << 56) +
607             (b56 << 48) +
608             (b48 << 40) +
609             (b40 << 32) +
610             (b32 << 24) +
611             (b24 << 16) +
612             (b16 << 8) +
613             b8);
614   }
615
616   /**
617    * Reads a byte from the stream.
618    */

619   public int readChar()
620     throws IOException JavaDoc
621   {
622     if (_chunkLength > 0) {
623       _chunkLength--;
624       if (_chunkLength == 0 && _isLastChunk)
625         _chunkLength = END_OF_DATA;
626
627       int ch = parseUTF8Char();
628       return ch;
629     }
630     else if (_chunkLength == END_OF_DATA) {
631       _chunkLength = 0;
632       return -1;
633     }
634     
635     int tag = read();
636
637     switch (tag) {
638     case 'N':
639       return -1;
640
641     case 'S':
642     case 's':
643     case 'X':
644     case 'x':
645       _isLastChunk = tag == 'S' || tag == 'X';
646       _chunkLength = (read() << 8) + read();
647
648       _chunkLength--;
649       int value = parseUTF8Char();
650
651       // special code so successive read byte won't
652
// be read as a single object.
653
if (_chunkLength == 0 && _isLastChunk)
654         _chunkLength = END_OF_DATA;
655
656       return value;
657       
658     default:
659       throw new IOException JavaDoc("expected 'S' at " + (char) tag);
660     }
661   }
662
663   /**
664    * Reads a byte array from the stream.
665    */

666   public int readString(char []buffer, int offset, int length)
667     throws IOException JavaDoc
668   {
669     int readLength = 0;
670
671     if (_chunkLength == END_OF_DATA) {
672       _chunkLength = 0;
673       return -1;
674     }
675     else if (_chunkLength == 0) {
676       int tag = read();
677
678       switch (tag) {
679       case 'N':
680         return -1;
681       
682       case 'S':
683       case 's':
684       case 'X':
685       case 'x':
686         _isLastChunk = tag == 'S' || tag == 'X';
687         _chunkLength = (read() << 8) + read();
688         break;
689
690       default:
691         throw new IOException JavaDoc("expected 'S' at " + (char) tag);
692       }
693     }
694
695     while (length > 0) {
696       if (_chunkLength > 0) {
697         buffer[offset++] = (char) parseUTF8Char();
698         _chunkLength--;
699         length--;
700         readLength++;
701       }
702       else if (_isLastChunk) {
703         if (readLength == 0)
704           return -1;
705         else {
706           _chunkLength = END_OF_DATA;
707           return readLength;
708         }
709       }
710       else {
711         int tag = read();
712
713         switch (tag) {
714         case 'S':
715         case 's':
716         case 'X':
717         case 'x':
718           _isLastChunk = tag == 'S' || tag == 'X';
719           _chunkLength = (read() << 8) + read();
720           break;
721       
722         default:
723           throw new IOException JavaDoc("expected 'S' at " + (char) tag);
724         }
725       }
726     }
727     
728     if (readLength == 0)
729       return -1;
730     else if (_chunkLength > 0 || ! _isLastChunk)
731       return readLength;
732     else {
733       _chunkLength = END_OF_DATA;
734       return readLength;
735     }
736   }
737
738   /**
739    * Reads a string
740    *
741    * <pre>
742    * S b16 b8 string value
743    * </pre>
744    */

745   public String JavaDoc readString()
746     throws IOException JavaDoc
747   {
748     int tag = read();
749
750     switch (tag) {
751     case 'N':
752       return null;
753
754     case 'I':
755       return String.valueOf(parseInt());
756     case 'L':
757       return String.valueOf(parseLong());
758     case 'D':
759       return String.valueOf(parseDouble());
760
761     case 'S':
762     case 's':
763     case 'X':
764     case 'x':
765       _isLastChunk = tag == 'S' || tag == 'X';
766       _chunkLength = (read() << 8) + read();
767
768       _sbuf.setLength(0);
769       int ch;
770
771       while ((ch = parseChar()) >= 0)
772         _sbuf.append((char) ch);
773
774       return _sbuf.toString();
775
776     default:
777       throw expect("string", tag);
778     }
779   }
780
781   /**
782    * Reads an XML node.
783    *
784    * <pre>
785    * S b16 b8 string value
786    * </pre>
787    */

788   public org.w3c.dom.Node JavaDoc readNode()
789     throws IOException JavaDoc
790   {
791     int tag = read();
792
793     switch (tag) {
794     case 'N':
795       return null;
796
797     case 'S':
798     case 's':
799     case 'X':
800     case 'x':
801       _isLastChunk = tag == 'S' || tag == 'X';
802       _chunkLength = (read() << 8) + read();
803
804       throw error("can't cope");
805
806     default:
807       throw expect("string", tag);
808     }
809   }
810
811   /**
812    * Reads a byte array
813    *
814    * <pre>
815    * B b16 b8 data value
816    * </pre>
817    */

818   public byte []readBytes()
819     throws IOException JavaDoc
820   {
821     int tag = read();
822
823     switch (tag) {
824     case 'N':
825       return null;
826
827     case 'B':
828     case 'b':
829       _isLastChunk = tag == 'B';
830       _chunkLength = (read() << 8) + read();
831
832       ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
833
834       int data;
835       while ((data = parseByte()) >= 0)
836         bos.write(data);
837
838       return bos.toByteArray();
839       
840     default:
841       throw expect("bytes", tag);
842     }
843   }
844
845   /**
846    * Reads a byte from the stream.
847    */

848   public int readByte()
849     throws IOException JavaDoc
850   {
851     if (_chunkLength > 0) {
852       _chunkLength--;
853       if (_chunkLength == 0 && _isLastChunk)
854         _chunkLength = END_OF_DATA;
855
856       return read();
857     }
858     else if (_chunkLength == END_OF_DATA) {
859       _chunkLength = 0;
860       return -1;
861     }
862     
863     int tag = read();
864
865     switch (tag) {
866     case 'N':
867       return -1;
868
869     case 'B':
870     case 'b':
871       _isLastChunk = tag == 'B';
872       _chunkLength = (read() << 8) + read();
873
874       int value = parseByte();
875
876       // special code so successive read byte won't
877
// be read as a single object.
878
if (_chunkLength == 0 && _isLastChunk)
879         _chunkLength = END_OF_DATA;
880
881       return value;
882       
883     default:
884       throw new IOException JavaDoc("expected 'B' at " + (char) tag);
885     }
886   }
887
888   /**
889    * Reads a byte array from the stream.
890    */

891   public int readBytes(byte []buffer, int offset, int length)
892     throws IOException JavaDoc
893   {
894     int readLength = 0;
895
896     if (_chunkLength == END_OF_DATA) {
897       _chunkLength = 0;
898       return -1;
899     }
900     else if (_chunkLength == 0) {
901       int tag = read();
902
903       switch (tag) {
904       case 'N':
905         return -1;
906       
907       case 'B':
908       case 'b':
909         _isLastChunk = tag == 'B';
910         _chunkLength = (read() << 8) + read();
911         break;
912       
913       default:
914         throw new IOException JavaDoc("expected 'B' at " + (char) tag);
915       }
916     }
917
918     while (length > 0) {
919       if (_chunkLength > 0) {
920         buffer[offset++] = (byte) read();
921         _chunkLength--;
922         length--;
923         readLength++;
924       }
925       else if (_isLastChunk) {
926         if (readLength == 0)
927           return -1;
928         else {
929           _chunkLength = END_OF_DATA;
930           return readLength;
931         }
932       }
933       else {
934         int tag = read();
935
936         switch (tag) {
937         case 'B':
938         case 'b':
939           _isLastChunk = tag == 'B';
940           _chunkLength = (read() << 8) + read();
941           break;
942       
943         default:
944           throw new IOException JavaDoc("expected 'B' at " + (char) tag);
945         }
946       }
947     }
948     
949     if (readLength == 0)
950       return -1;
951     else if (_chunkLength > 0 || ! _isLastChunk)
952       return readLength;
953     else {
954       _chunkLength = END_OF_DATA;
955       return readLength;
956     }
957   }
958
959   /**
960    * Reads a fault.
961    */

962   private HashMap JavaDoc readFault()
963     throws IOException JavaDoc
964   {
965     HashMap JavaDoc map = new HashMap JavaDoc();
966
967     int code = read();
968     for (; code > 0 && code != 'z'; code = read()) {
969       _peek = code;
970       
971       Object JavaDoc key = readObject();
972       Object JavaDoc value = readObject();
973
974       if (key != null && value != null)
975         map.put(key, value);
976     }
977
978     if (code != 'z')
979       throw expect("fault", code);
980
981     return map;
982   }
983
984   /**
985    * Reads an object from the input stream with an expected type.
986    */

987   public Object JavaDoc readObject(Class JavaDoc cl)
988     throws IOException JavaDoc
989   {
990     if (cl == null || cl == Object JavaDoc.class)
991       return readObject();
992     
993     int tag = read();
994     
995     switch (tag) {
996     case 'N':
997       return null;
998
999     case 'M':
1000    {
1001      String JavaDoc type = readType();
1002      Deserializer reader;
1003      reader = _serializerFactory.getObjectDeserializer(type);
1004
1005      if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))
1006        return reader.readMap(this);
1007
1008      reader = _serializerFactory.getDeserializer(cl);
1009
1010      return reader.readMap(this);
1011    }
1012
1013    case 'V':
1014    {
1015      String JavaDoc type = readType();
1016      int length = readLength();
1017      
1018      Deserializer reader;
1019      reader = _serializerFactory.getObjectDeserializer(type);
1020      
1021      if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))
1022        return reader.readList(this, length);
1023
1024      reader = _serializerFactory.getDeserializer(cl);
1025
1026      Object JavaDoc v = reader.readList(this, length);
1027
1028      return v;
1029    }
1030
1031    case 'R':
1032    {
1033      int ref = parseInt();
1034
1035      return _refs.get(ref);
1036    }
1037
1038    case 'r':
1039    {
1040      String JavaDoc type = readType();
1041      String JavaDoc url = readString();
1042
1043      return resolveRemote(type, url);
1044    }
1045    }
1046
1047    _peek = tag;
1048
1049    Object JavaDoc value = _serializerFactory.getDeserializer(cl).readObject(this);
1050
1051    return value;
1052  }
1053  
1054  /**
1055   * Reads an arbitrary object from the input stream when the type
1056   * is unknown.
1057   */

1058  public Object JavaDoc readObject()
1059    throws IOException JavaDoc
1060  {
1061    int tag = read();
1062
1063    switch (tag) {
1064    case 'N':
1065      return null;
1066      
1067    case 'T':
1068      return new Boolean JavaDoc(true);
1069      
1070    case 'F':
1071      return new Boolean JavaDoc(false);
1072      
1073    case 'I':
1074      return new Integer JavaDoc(parseInt());
1075    
1076    case 'L':
1077      return new Long JavaDoc(parseLong());
1078    
1079    case 'D':
1080      return new Double JavaDoc(parseDouble());
1081    
1082    case 'd':
1083      return new Date JavaDoc(parseLong());
1084    
1085    case 'x':
1086    case 'X': {
1087      _isLastChunk = tag == 'X';
1088      _chunkLength = (read() << 8) + read();
1089
1090      return parseXML();
1091    }
1092
1093    case 's':
1094    case 'S': {
1095      _isLastChunk = tag == 'S';
1096      _chunkLength = (read() << 8) + read();
1097
1098      int data;
1099      _sbuf.setLength(0);
1100      
1101      while ((data = parseChar()) >= 0)
1102        _sbuf.append((char) data);
1103
1104      return _sbuf.toString();
1105    }
1106
1107    case 'b':
1108    case 'B': {
1109      _isLastChunk = tag == 'B';
1110      _chunkLength = (read() << 8) + read();
1111
1112      int data;
1113      ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
1114      
1115      while ((data = parseByte()) >= 0)
1116        bos.write(data);
1117
1118      return bos.toByteArray();
1119    }
1120
1121    case 'V': {
1122      String JavaDoc type = readType();
1123      int length = readLength();
1124
1125      return _serializerFactory.readList(this, length, type);
1126    }
1127
1128    case 'M': {
1129      String JavaDoc type = readType();
1130
1131      return _serializerFactory.readMap(this, type);
1132    }
1133
1134    case 'R': {
1135      int ref = parseInt();
1136
1137      return _refs.get(ref);
1138    }
1139
1140    case 'r': {
1141      String JavaDoc type = readType();
1142      String JavaDoc url = readString();
1143
1144      return resolveRemote(type, url);
1145    }
1146
1147    default:
1148      throw error("unknown code:" + (char) tag);
1149    }
1150  }
1151
1152  /**
1153   * Reads a remote object.
1154   */

1155  public Object JavaDoc readRemote()
1156    throws IOException JavaDoc
1157  {
1158    String JavaDoc type = readType();
1159    String JavaDoc url = readString();
1160
1161    return resolveRemote(type, url);
1162  }
1163
1164  /**
1165   * Reads a reference.
1166   */

1167  public Object JavaDoc readRef()
1168    throws IOException JavaDoc
1169  {
1170    return _refs.get(parseInt());
1171  }
1172
1173  /**
1174   * Reads the start of a list.
1175   */

1176  public int readListStart()
1177    throws IOException JavaDoc
1178  {
1179    return read();
1180  }
1181
1182  /**
1183   * Reads the start of a list.
1184   */

1185  public int readMapStart()
1186    throws IOException JavaDoc
1187  {
1188    return read();
1189  }
1190
1191  /**
1192   * Returns true if this is the end of a list or a map.
1193   */

1194  public boolean isEnd()
1195    throws IOException JavaDoc
1196  {
1197    int code = read();
1198
1199    _peek = code;
1200
1201    return (code < 0 || code == 'z');
1202  }
1203
1204  /**
1205   * Reads the end byte.
1206   */

1207  public void readEnd()
1208    throws IOException JavaDoc
1209  {
1210    int code = read();
1211
1212    if (code != 'z')
1213      throw error("unknown code:" + (char) code);
1214  }
1215
1216  /**
1217   * Reads the end byte.
1218   */

1219  public void readMapEnd()
1220    throws IOException JavaDoc
1221  {
1222    int code = read();
1223
1224    if (code != 'z')
1225      throw error("expected end of map ('z') at '" + (char) code + "'");
1226  }
1227
1228  /**
1229   * Reads the end byte.
1230   */

1231  public void readListEnd()
1232    throws IOException JavaDoc
1233  {
1234    int code = read();
1235
1236    if (code != 'z')
1237      throw error("expected end of list ('z') at '" + (char) code + "'");
1238  }
1239
1240  /**
1241   * Adds a list/map reference.
1242   */

1243  public int addRef(Object JavaDoc ref)
1244  {
1245    if (_refs == null)
1246      _refs = new ArrayList JavaDoc();
1247    
1248    _refs.add(ref);
1249
1250    return _refs.size() - 1;
1251  }
1252
1253  /**
1254   * Adds a list/map reference.
1255   */

1256  public void setRef(int i, Object JavaDoc ref)
1257  {
1258    _refs.set(i, ref);
1259  }
1260
1261  /**
1262   * Resolves a remote object.
1263   */

1264  public Object JavaDoc resolveRemote(String JavaDoc type, String JavaDoc url)
1265    throws IOException JavaDoc
1266  {
1267    HessianRemoteResolver resolver = getRemoteResolver();
1268
1269    if (resolver != null)
1270      return resolver.lookup(type, url);
1271    else
1272      return new HessianRemote(type, url);
1273  }
1274
1275  /**
1276   * Parses a type from the stream.
1277   *
1278   * <pre>
1279   * t b16 b8
1280   * </pre>
1281   */

1282  public String JavaDoc readType()
1283    throws IOException JavaDoc
1284  {
1285    int code = read();
1286
1287    if (code != 't') {
1288      _peek = code;
1289      return "";
1290    }
1291
1292    _isLastChunk = true;
1293    _chunkLength = (read() << 8) + read();
1294
1295    _sbuf.setLength(0);
1296    int ch;
1297    while ((ch = parseChar()) >= 0)
1298      _sbuf.append((char) ch);
1299
1300    return _sbuf.toString();
1301  }
1302
1303  /**
1304   * Parses the length for an array
1305   *
1306   * <pre>
1307   * l b32 b24 b16 b8
1308   * </pre>
1309   */

1310  public int readLength()
1311    throws IOException JavaDoc
1312  {
1313    int code = read();
1314
1315    if (code != 'l') {
1316      _peek = code;
1317      return -1;
1318    }
1319
1320    return parseInt();
1321  }
1322
1323  /**
1324   * Parses a 32-bit integer value from the stream.
1325   *
1326   * <pre>
1327   * b32 b24 b16 b8
1328   * </pre>
1329   */

1330  private int parseInt()
1331    throws IOException JavaDoc
1332  {
1333    int b32 = read();
1334    int b24 = read();
1335    int b16 = read();
1336    int b8 = read();
1337
1338    return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
1339  }
1340
1341  /**
1342   * Parses a 64-bit long value from the stream.
1343   *
1344   * <pre>
1345   * b64 b56 b48 b40 b32 b24 b16 b8
1346   * </pre>
1347   */

1348  private long parseLong()
1349    throws IOException JavaDoc
1350  {
1351    long b64 = read();
1352    long b56 = read();
1353    long b48 = read();
1354    long b40 = read();
1355    long b32 = read();
1356    long b24 = read();
1357    long b16 = read();
1358    long b8 = read();
1359
1360    return ((b64 << 56) +
1361            (b56 << 48) +
1362            (b48 << 40) +
1363            (b40 << 32) +
1364            (b32 << 24) +
1365            (b24 << 16) +
1366            (b16 << 8) +
1367            b8);
1368  }
1369  
1370  /**
1371   * Parses a 64-bit double value from the stream.
1372   *
1373   * <pre>
1374   * b64 b56 b48 b40 b32 b24 b16 b8
1375   * </pre>
1376   */

1377  private double parseDouble()
1378    throws IOException JavaDoc
1379  {
1380    long b64 = read();
1381    long b56 = read();
1382    long b48 = read();
1383    long b40 = read();
1384    long b32 = read();
1385    long b24 = read();
1386    long b16 = read();
1387    long b8 = read();
1388
1389    long bits = ((b64 << 56) +
1390                 (b56 << 48) +
1391                 (b48 << 40) +
1392                 (b40 << 32) +
1393                 (b32 << 24) +
1394                 (b24 << 16) +
1395                 (b16 << 8) +
1396                 b8);
1397  
1398    return Double.longBitsToDouble(bits);
1399  }
1400
1401  org.w3c.dom.Node JavaDoc parseXML()
1402    throws IOException JavaDoc
1403  {
1404    throw new UnsupportedOperationException JavaDoc();
1405  }
1406  
1407  /**
1408   * Reads a character from the underlying stream.
1409   */

1410  private int parseChar()
1411    throws IOException JavaDoc
1412  {
1413    while (_chunkLength <= 0) {
1414      if (_isLastChunk)
1415        return -1;
1416
1417      int code = read();
1418
1419      switch (code) {
1420      case 's':
1421      case 'x':
1422        _isLastChunk = false;
1423
1424        _chunkLength = (read() << 8) + read();
1425        break;
1426        
1427      case 'S':
1428      case 'X':
1429        _isLastChunk = true;
1430
1431        _chunkLength = (read() << 8) + read();
1432        break;
1433
1434      default:
1435        throw expect("string", code);
1436      }
1437
1438    }
1439
1440    _chunkLength--;
1441
1442    return parseUTF8Char();
1443  }
1444
1445  /**
1446   * Parses a single UTF8 character.
1447   */

1448  private int parseUTF8Char()
1449    throws IOException JavaDoc
1450  {
1451    int ch = read();
1452
1453    if (ch < 0x80)
1454      return ch;
1455    else if ((ch & 0xe0) == 0xc0) {
1456      int ch1 = read();
1457      int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
1458
1459      return v;
1460    }
1461    else if ((ch & 0xf0) == 0xe0) {
1462      int ch1 = read();
1463      int ch2 = read();
1464      int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f);
1465
1466      return v;
1467    }
1468    else
1469      throw error("bad utf-8 encoding");
1470  }
1471  
1472  /**
1473   * Reads a byte from the underlying stream.
1474   */

1475  private int parseByte()
1476    throws IOException JavaDoc
1477  {
1478    while (_chunkLength <= 0) {
1479      if (_isLastChunk) {
1480        return -1;
1481      }
1482
1483      int code = read();
1484
1485      switch (code) {
1486      case 'b':
1487        _isLastChunk = false;
1488
1489        _chunkLength = (read() << 8) + read();
1490        break;
1491        
1492      case 'B':
1493        _isLastChunk = true;
1494
1495        _chunkLength = (read() << 8) + read();
1496        break;
1497
1498      default:
1499        throw expect("byte[]", code);
1500      }
1501    }
1502
1503    _chunkLength--;
1504
1505    return read();
1506  }
1507
1508  /**
1509   * Reads bytes based on an input stream.
1510   */

1511  public InputStream JavaDoc readInputStream()
1512    throws IOException JavaDoc
1513  {
1514    int tag = read();
1515
1516    switch (tag) {
1517    case 'N':
1518      return null;
1519
1520    case 'B':
1521    case 'b':
1522      _isLastChunk = tag == 'B';
1523      _chunkLength = (read() << 8) + read();
1524      break;
1525      
1526    default:
1527      throw expect("inputStream", tag);
1528    }
1529    
1530    return new InputStream JavaDoc() {
1531    boolean _isClosed = false;
1532    
1533    public int read()
1534      throws IOException JavaDoc
1535    {
1536      if (_isClosed)
1537        return -1;
1538
1539      int ch = parseByte();
1540      if (ch < 0)
1541        _isClosed = true;
1542
1543      return ch;
1544    }
1545    
1546    public int read(byte []buffer, int offset, int length)
1547      throws IOException JavaDoc
1548    {
1549      if (_isClosed)
1550        return -1;
1551
1552      int len = HessianInput.this.read(buffer, offset, length);
1553      if (len < 0)
1554        _isClosed = true;
1555
1556      return len;
1557    }
1558
1559    public void close()
1560      throws IOException JavaDoc
1561    {
1562      while (read() >= 0) {
1563      }
1564    }
1565      };
1566  }
1567  
1568  /**
1569   * Reads bytes from the underlying stream.
1570   */

1571  int read(byte []buffer, int offset, int length)
1572    throws IOException JavaDoc
1573  {
1574    int readLength = 0;
1575    
1576    while (length > 0) {
1577      while (_chunkLength <= 0) {
1578        if (_isLastChunk)
1579          return readLength == 0 ? -1 : readLength;
1580
1581        int code = read();
1582
1583        switch (code) {
1584        case 'b':
1585          _isLastChunk = false;
1586
1587          _chunkLength = (read() << 8) + read();
1588          break;
1589        
1590        case 'B':
1591          _isLastChunk = true;
1592
1593          _chunkLength = (read() << 8) + read();
1594          break;
1595
1596        default:
1597          throw expect("byte[]", code);
1598        }
1599      }
1600
1601      int sublen = _chunkLength;
1602      if (length < sublen)
1603        sublen = length;
1604
1605      sublen = _is.read(buffer, offset, sublen);
1606      offset += sublen;
1607      readLength += sublen;
1608      length -= sublen;
1609      _chunkLength -= sublen;
1610    }
1611
1612    return readLength;
1613  }
1614
1615  final int read()
1616    throws IOException JavaDoc
1617  {
1618    if (_peek >= 0) {
1619      int value = _peek;
1620      _peek = -1;
1621      return value;
1622    }
1623
1624    int ch = _is.read();
1625      
1626    return ch;
1627  }
1628
1629  public Reader JavaDoc getReader()
1630  {
1631    return null;
1632  }
1633
1634  protected IOException JavaDoc expect(String JavaDoc expect, int ch)
1635  {
1636    if (ch < 0)
1637      return error("expected " + expect + " at end of file");
1638    else
1639      return error("expected " + expect + " at " + (char) ch);
1640  }
1641  
1642  protected IOException JavaDoc error(String JavaDoc message)
1643  {
1644    if (_method != null)
1645      return new HessianProtocolException(_method + ": " + message);
1646    else
1647      return new HessianProtocolException(message);
1648  }
1649
1650  static {
1651    try {
1652      _detailMessageField = Throwable JavaDoc.class.getDeclaredField("detailMessage");
1653      _detailMessageField.setAccessible(true);
1654    } catch (Throwable JavaDoc e) {
1655    }
1656  }
1657}
1658
Popular Tags