0001: /*
0002: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
0003: *
0004: * The Apache Software License, Version 1.1
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution, if
0019: * any, must include the following acknowlegement:
0020: * "This product includes software developed by the
0021: * Caucho Technology (http://www.caucho.com/)."
0022: * Alternately, this acknowlegement may appear in the software itself,
0023: * if and wherever such third-party acknowlegements normally appear.
0024: *
0025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
0026: * endorse or promote products derived from this software without prior
0027: * written permission. For written permission, please contact
0028: * info@caucho.com.
0029: *
0030: * 5. Products derived from this software may not be called "Resin"
0031: * nor may "Resin" appear in their names without prior written
0032: * permission of Caucho Technology.
0033: *
0034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
0038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
0039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
0040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
0041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
0043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
0044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0045: *
0046: * @author Scott Ferguson
0047: */
0048:
0049: package com.caucho.hessian.io;
0050:
0051: import java.io.ByteArrayOutputStream;
0052: import java.io.IOException;
0053: import java.io.InputStream;
0054: import java.io.Reader;
0055: import java.lang.reflect.Field;
0056: import java.util.ArrayList;
0057: import java.util.Date;
0058: import java.util.HashMap;
0059:
0060: /**
0061: * Input stream for Hessian requests.
0062: *
0063: * <p>HessianInput is unbuffered, so any client needs to provide
0064: * its own buffering.
0065: *
0066: * <pre>
0067: * InputStream is = ...; // from http connection
0068: * HessianInput in = new HessianInput(is);
0069: * String value;
0070: *
0071: * in.startReply(); // read reply header
0072: * value = in.readString(); // read string value
0073: * in.completeReply(); // read reply footer
0074: * </pre>
0075: */
0076: public class HessianInput extends AbstractHessianInput {
0077: private static int END_OF_DATA = -2;
0078:
0079: private static Field _detailMessageField;
0080:
0081: // factory for deserializing objects in the input stream
0082: protected SerializerFactory _serializerFactory;
0083:
0084: protected ArrayList _refs;
0085:
0086: // the underlying input stream
0087: private InputStream _is;
0088: // a peek character
0089: protected int _peek = -1;
0090:
0091: // the method for a call
0092: private String _method;
0093:
0094: private Reader _chunkReader;
0095: private InputStream _chunkInputStream;
0096:
0097: private Throwable _replyFault;
0098:
0099: private StringBuffer _sbuf = new StringBuffer();
0100:
0101: // true if this is the last chunk
0102: private boolean _isLastChunk;
0103: // the chunk length
0104: private int _chunkLength;
0105:
0106: /**
0107: * Creates an uninitialized Hessian input stream.
0108: */
0109: public HessianInput() {
0110: }
0111:
0112: /**
0113: * Creates a new Hessian input stream, initialized with an
0114: * underlying input stream.
0115: *
0116: * @param is the underlying input stream.
0117: */
0118: public HessianInput(InputStream is) {
0119: init(is);
0120: }
0121:
0122: /**
0123: * Sets the serializer factory.
0124: */
0125: public void setSerializerFactory(SerializerFactory factory) {
0126: _serializerFactory = factory;
0127: }
0128:
0129: /**
0130: * Gets the serializer factory.
0131: */
0132: public SerializerFactory getSerializerFactory() {
0133: return _serializerFactory;
0134: }
0135:
0136: /**
0137: * Initialize the hessian stream with the underlying input stream.
0138: */
0139: public void init(InputStream is) {
0140: _is = is;
0141: _method = null;
0142: _isLastChunk = true;
0143: _chunkLength = 0;
0144: _peek = -1;
0145: _refs = null;
0146: _replyFault = null;
0147:
0148: if (_serializerFactory == null)
0149: _serializerFactory = new SerializerFactory();
0150: }
0151:
0152: /**
0153: * Returns the calls method
0154: */
0155: public String getMethod() {
0156: return _method;
0157: }
0158:
0159: /**
0160: * Returns any reply fault.
0161: */
0162: public Throwable getReplyFault() {
0163: return _replyFault;
0164: }
0165:
0166: /**
0167: * Starts reading the call
0168: *
0169: * <pre>
0170: * c major minor
0171: * </pre>
0172: */
0173: public int readCall() throws IOException {
0174: int tag = read();
0175:
0176: if (tag != 'c')
0177: throw error("expected hessian call ('c') at "
0178: + codeName(tag));
0179:
0180: int major = read();
0181: int minor = read();
0182:
0183: return (major << 16) + minor;
0184: }
0185:
0186: /**
0187: * For backward compatibility with HessianSkeleton
0188: */
0189: public void skipOptionalCall() throws IOException {
0190: int tag = read();
0191:
0192: if (tag == 'c') {
0193: read();
0194: read();
0195: } else
0196: _peek = tag;
0197: }
0198:
0199: /**
0200: * Starts reading the call
0201: *
0202: * <p>A successful completion will have a single value:
0203: *
0204: * <pre>
0205: * m b16 b8 method
0206: * </pre>
0207: */
0208: public String readMethod() throws IOException {
0209: int tag = read();
0210:
0211: if (tag != 'm')
0212: throw error("expected hessian method ('m') at "
0213: + codeName(tag));
0214: int d1 = read();
0215: int d2 = read();
0216:
0217: _isLastChunk = true;
0218: _chunkLength = d1 * 256 + d2;
0219: _sbuf.setLength(0);
0220: int ch;
0221: while ((ch = parseChar()) >= 0)
0222: _sbuf.append((char) ch);
0223:
0224: _method = _sbuf.toString();
0225:
0226: return _method;
0227: }
0228:
0229: /**
0230: * Starts reading the call, including the headers.
0231: *
0232: * <p>The call expects the following protocol data
0233: *
0234: * <pre>
0235: * c major minor
0236: * m b16 b8 method
0237: * </pre>
0238: */
0239: public void startCall() throws IOException {
0240: readCall();
0241:
0242: while (readHeader() != null) {
0243: readObject();
0244: }
0245:
0246: readMethod();
0247: }
0248:
0249: /**
0250: * Completes reading the call
0251: *
0252: * <p>A successful completion will have a single value:
0253: *
0254: * <pre>
0255: * z
0256: * </pre>
0257: */
0258: public void completeCall() throws IOException {
0259: int tag = read();
0260:
0261: if (tag == 'z') {
0262: } else
0263: throw error("expected end of call ('z') at "
0264: + codeName(tag)
0265: + ". Check method arguments and ensure method overloading is enabled if necessary");
0266: }
0267:
0268: /**
0269: * Reads a reply as an object.
0270: * If the reply has a fault, throws the exception.
0271: */
0272: public Object readReply(Class expectedClass) throws Throwable {
0273: int tag = read();
0274:
0275: if (tag != 'r')
0276: error("expected hessian reply at " + codeName(tag));
0277:
0278: int major = read();
0279: int minor = read();
0280:
0281: tag = read();
0282: if (tag == 'f')
0283: throw prepareFault();
0284: else {
0285: _peek = tag;
0286:
0287: Object value = readObject(expectedClass);
0288:
0289: completeValueReply();
0290:
0291: return value;
0292: }
0293: }
0294:
0295: /**
0296: * Starts reading the reply
0297: *
0298: * <p>A successful completion will have a single value:
0299: *
0300: * <pre>
0301: * r
0302: * </pre>
0303: */
0304: public void startReply() throws Throwable {
0305: int tag = read();
0306:
0307: if (tag != 'r')
0308: error("expected hessian reply at " + codeName(tag));
0309:
0310: int major = read();
0311: int minor = read();
0312:
0313: tag = read();
0314: if (tag == 'f')
0315: throw prepareFault();
0316: else
0317: _peek = tag;
0318: }
0319:
0320: /**
0321: * Prepares the fault.
0322: */
0323: private Throwable prepareFault() throws IOException {
0324: HashMap fault = readFault();
0325:
0326: Object detail = fault.get("detail");
0327: String message = (String) fault.get("message");
0328:
0329: if (detail instanceof Throwable) {
0330: _replyFault = (Throwable) detail;
0331:
0332: if (message != null && _detailMessageField != null) {
0333: try {
0334: _detailMessageField.set(_replyFault, message);
0335: } catch (Throwable e) {
0336: }
0337: }
0338:
0339: return _replyFault;
0340: }
0341:
0342: else {
0343: String code = (String) fault.get("code");
0344:
0345: _replyFault = new HessianServiceException(message, code,
0346: detail);
0347:
0348: return _replyFault;
0349: }
0350: }
0351:
0352: /**
0353: * Completes reading the call
0354: *
0355: * <p>A successful completion will have a single value:
0356: *
0357: * <pre>
0358: * z
0359: * </pre>
0360: */
0361: public void completeReply() throws IOException {
0362: int tag = read();
0363:
0364: if (tag != 'z')
0365: error("expected end of reply at " + codeName(tag));
0366: }
0367:
0368: /**
0369: * Completes reading the call
0370: *
0371: * <p>A successful completion will have a single value:
0372: *
0373: * <pre>
0374: * z
0375: * </pre>
0376: */
0377: public void completeValueReply() throws IOException {
0378: int tag = read();
0379:
0380: if (tag != 'z')
0381: error("expected end of reply at " + codeName(tag));
0382: }
0383:
0384: /**
0385: * Reads a header, returning null if there are no headers.
0386: *
0387: * <pre>
0388: * H b16 b8 value
0389: * </pre>
0390: */
0391: public String readHeader() throws IOException {
0392: int tag = read();
0393:
0394: if (tag == 'H') {
0395: _isLastChunk = true;
0396: _chunkLength = (read() << 8) + read();
0397:
0398: _sbuf.setLength(0);
0399: int ch;
0400: while ((ch = parseChar()) >= 0)
0401: _sbuf.append((char) ch);
0402:
0403: return _sbuf.toString();
0404: }
0405:
0406: _peek = tag;
0407:
0408: return null;
0409: }
0410:
0411: /**
0412: * Reads a null
0413: *
0414: * <pre>
0415: * N
0416: * </pre>
0417: */
0418: public void readNull() throws IOException {
0419: int tag = read();
0420:
0421: switch (tag) {
0422: case 'N':
0423: return;
0424:
0425: default:
0426: throw expect("null", tag);
0427: }
0428: }
0429:
0430: /**
0431: * Reads a boolean
0432: *
0433: * <pre>
0434: * T
0435: * F
0436: * </pre>
0437: */
0438: public boolean readBoolean() throws IOException {
0439: int tag = read();
0440:
0441: switch (tag) {
0442: case 'T':
0443: return true;
0444: case 'F':
0445: return false;
0446: case 'I':
0447: return parseInt() == 0;
0448: case 'L':
0449: return parseLong() == 0;
0450: case 'D':
0451: return parseDouble() == 0.0;
0452: case 'N':
0453: return false;
0454:
0455: default:
0456: throw expect("boolean", tag);
0457: }
0458: }
0459:
0460: /**
0461: * Reads a byte
0462: *
0463: * <pre>
0464: * I b32 b24 b16 b8
0465: * </pre>
0466: */
0467: /*
0468: public byte readByte()
0469: throws IOException
0470: {
0471: return (byte) readInt();
0472: }
0473: */
0474:
0475: /**
0476: * Reads a short
0477: *
0478: * <pre>
0479: * I b32 b24 b16 b8
0480: * </pre>
0481: */
0482: public short readShort() throws IOException {
0483: return (short) readInt();
0484: }
0485:
0486: /**
0487: * Reads an integer
0488: *
0489: * <pre>
0490: * I b32 b24 b16 b8
0491: * </pre>
0492: */
0493: public int readInt() throws IOException {
0494: int tag = read();
0495:
0496: switch (tag) {
0497: case 'T':
0498: return 1;
0499: case 'F':
0500: return 0;
0501: case 'I':
0502: return parseInt();
0503: case 'L':
0504: return (int) parseLong();
0505: case 'D':
0506: return (int) parseDouble();
0507:
0508: default:
0509: throw expect("int", tag);
0510: }
0511: }
0512:
0513: /**
0514: * Reads a long
0515: *
0516: * <pre>
0517: * L b64 b56 b48 b40 b32 b24 b16 b8
0518: * </pre>
0519: */
0520: public long readLong() throws IOException {
0521: int tag = read();
0522:
0523: switch (tag) {
0524: case 'T':
0525: return 1;
0526: case 'F':
0527: return 0;
0528: case 'I':
0529: return parseInt();
0530: case 'L':
0531: return parseLong();
0532: case 'D':
0533: return (long) parseDouble();
0534:
0535: default:
0536: throw expect("long", tag);
0537: }
0538: }
0539:
0540: /**
0541: * Reads a float
0542: *
0543: * <pre>
0544: * D b64 b56 b48 b40 b32 b24 b16 b8
0545: * </pre>
0546: */
0547: public float readFloat() throws IOException {
0548: return (float) readDouble();
0549: }
0550:
0551: /**
0552: * Reads a double
0553: *
0554: * <pre>
0555: * D b64 b56 b48 b40 b32 b24 b16 b8
0556: * </pre>
0557: */
0558: public double readDouble() throws IOException {
0559: int tag = read();
0560:
0561: switch (tag) {
0562: case 'T':
0563: return 1;
0564: case 'F':
0565: return 0;
0566: case 'I':
0567: return parseInt();
0568: case 'L':
0569: return (double) parseLong();
0570: case 'D':
0571: return parseDouble();
0572:
0573: default:
0574: throw expect("long", tag);
0575: }
0576: }
0577:
0578: /**
0579: * Reads a date.
0580: *
0581: * <pre>
0582: * T b64 b56 b48 b40 b32 b24 b16 b8
0583: * </pre>
0584: */
0585: public long readUTCDate() throws IOException {
0586: int tag = read();
0587:
0588: if (tag != 'd')
0589: throw error("expected date at " + codeName(tag));
0590:
0591: long b64 = read();
0592: long b56 = read();
0593: long b48 = read();
0594: long b40 = read();
0595: long b32 = read();
0596: long b24 = read();
0597: long b16 = read();
0598: long b8 = read();
0599:
0600: return ((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32)
0601: + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8);
0602: }
0603:
0604: /**
0605: * Reads a byte from the stream.
0606: */
0607: public int readChar() throws IOException {
0608: if (_chunkLength > 0) {
0609: _chunkLength--;
0610: if (_chunkLength == 0 && _isLastChunk)
0611: _chunkLength = END_OF_DATA;
0612:
0613: int ch = parseUTF8Char();
0614: return ch;
0615: } else if (_chunkLength == END_OF_DATA) {
0616: _chunkLength = 0;
0617: return -1;
0618: }
0619:
0620: int tag = read();
0621:
0622: switch (tag) {
0623: case 'N':
0624: return -1;
0625:
0626: case 'S':
0627: case 's':
0628: case 'X':
0629: case 'x':
0630: _isLastChunk = tag == 'S' || tag == 'X';
0631: _chunkLength = (read() << 8) + read();
0632:
0633: _chunkLength--;
0634: int value = parseUTF8Char();
0635:
0636: // special code so successive read byte won't
0637: // be read as a single object.
0638: if (_chunkLength == 0 && _isLastChunk)
0639: _chunkLength = END_OF_DATA;
0640:
0641: return value;
0642:
0643: default:
0644: throw new IOException("expected 'S' at " + (char) tag);
0645: }
0646: }
0647:
0648: /**
0649: * Reads a byte array from the stream.
0650: */
0651: public int readString(char[] buffer, int offset, int length)
0652: throws IOException {
0653: int readLength = 0;
0654:
0655: if (_chunkLength == END_OF_DATA) {
0656: _chunkLength = 0;
0657: return -1;
0658: } else if (_chunkLength == 0) {
0659: int tag = read();
0660:
0661: switch (tag) {
0662: case 'N':
0663: return -1;
0664:
0665: case 'S':
0666: case 's':
0667: case 'X':
0668: case 'x':
0669: _isLastChunk = tag == 'S' || tag == 'X';
0670: _chunkLength = (read() << 8) + read();
0671: break;
0672:
0673: default:
0674: throw new IOException("expected 'S' at " + (char) tag);
0675: }
0676: }
0677:
0678: while (length > 0) {
0679: if (_chunkLength > 0) {
0680: buffer[offset++] = (char) parseUTF8Char();
0681: _chunkLength--;
0682: length--;
0683: readLength++;
0684: } else if (_isLastChunk) {
0685: if (readLength == 0)
0686: return -1;
0687: else {
0688: _chunkLength = END_OF_DATA;
0689: return readLength;
0690: }
0691: } else {
0692: int tag = read();
0693:
0694: switch (tag) {
0695: case 'S':
0696: case 's':
0697: case 'X':
0698: case 'x':
0699: _isLastChunk = tag == 'S' || tag == 'X';
0700: _chunkLength = (read() << 8) + read();
0701: break;
0702:
0703: default:
0704: throw new IOException("expected 'S' at "
0705: + (char) tag);
0706: }
0707: }
0708: }
0709:
0710: if (readLength == 0)
0711: return -1;
0712: else if (_chunkLength > 0 || !_isLastChunk)
0713: return readLength;
0714: else {
0715: _chunkLength = END_OF_DATA;
0716: return readLength;
0717: }
0718: }
0719:
0720: /**
0721: * Reads a string
0722: *
0723: * <pre>
0724: * S b16 b8 string value
0725: * </pre>
0726: */
0727: public String readString() throws IOException {
0728: int tag = read();
0729:
0730: switch (tag) {
0731: case 'N':
0732: return null;
0733:
0734: case 'I':
0735: return String.valueOf(parseInt());
0736: case 'L':
0737: return String.valueOf(parseLong());
0738: case 'D':
0739: return String.valueOf(parseDouble());
0740:
0741: case 'S':
0742: case 's':
0743: case 'X':
0744: case 'x':
0745: _isLastChunk = tag == 'S' || tag == 'X';
0746: _chunkLength = (read() << 8) + read();
0747:
0748: _sbuf.setLength(0);
0749: int ch;
0750:
0751: while ((ch = parseChar()) >= 0)
0752: _sbuf.append((char) ch);
0753:
0754: return _sbuf.toString();
0755:
0756: default:
0757: throw expect("string", tag);
0758: }
0759: }
0760:
0761: /**
0762: * Reads an XML node.
0763: *
0764: * <pre>
0765: * S b16 b8 string value
0766: * </pre>
0767: */
0768: public org.w3c.dom.Node readNode() throws IOException {
0769: int tag = read();
0770:
0771: switch (tag) {
0772: case 'N':
0773: return null;
0774:
0775: case 'S':
0776: case 's':
0777: case 'X':
0778: case 'x':
0779: _isLastChunk = tag == 'S' || tag == 'X';
0780: _chunkLength = (read() << 8) + read();
0781:
0782: throw error("Can't handle string in this context");
0783:
0784: default:
0785: throw expect("string", tag);
0786: }
0787: }
0788:
0789: /**
0790: * Reads a byte array
0791: *
0792: * <pre>
0793: * B b16 b8 data value
0794: * </pre>
0795: */
0796: public byte[] readBytes() throws IOException {
0797: int tag = read();
0798:
0799: switch (tag) {
0800: case 'N':
0801: return null;
0802:
0803: case 'B':
0804: case 'b':
0805: _isLastChunk = tag == 'B';
0806: _chunkLength = (read() << 8) + read();
0807:
0808: ByteArrayOutputStream bos = new ByteArrayOutputStream();
0809:
0810: int data;
0811: while ((data = parseByte()) >= 0)
0812: bos.write(data);
0813:
0814: return bos.toByteArray();
0815:
0816: default:
0817: throw expect("bytes", tag);
0818: }
0819: }
0820:
0821: /**
0822: * Reads a byte from the stream.
0823: */
0824: public int readByte() throws IOException {
0825: if (_chunkLength > 0) {
0826: _chunkLength--;
0827: if (_chunkLength == 0 && _isLastChunk)
0828: _chunkLength = END_OF_DATA;
0829:
0830: return read();
0831: } else if (_chunkLength == END_OF_DATA) {
0832: _chunkLength = 0;
0833: return -1;
0834: }
0835:
0836: int tag = read();
0837:
0838: switch (tag) {
0839: case 'N':
0840: return -1;
0841:
0842: case 'B':
0843: case 'b':
0844: _isLastChunk = tag == 'B';
0845: _chunkLength = (read() << 8) + read();
0846:
0847: int value = parseByte();
0848:
0849: // special code so successive read byte won't
0850: // be read as a single object.
0851: if (_chunkLength == 0 && _isLastChunk)
0852: _chunkLength = END_OF_DATA;
0853:
0854: return value;
0855:
0856: default:
0857: throw new IOException("expected 'B' at " + (char) tag);
0858: }
0859: }
0860:
0861: /**
0862: * Reads a byte array from the stream.
0863: */
0864: public int readBytes(byte[] buffer, int offset, int length)
0865: throws IOException {
0866: int readLength = 0;
0867:
0868: if (_chunkLength == END_OF_DATA) {
0869: _chunkLength = 0;
0870: return -1;
0871: } else if (_chunkLength == 0) {
0872: int tag = read();
0873:
0874: switch (tag) {
0875: case 'N':
0876: return -1;
0877:
0878: case 'B':
0879: case 'b':
0880: _isLastChunk = tag == 'B';
0881: _chunkLength = (read() << 8) + read();
0882: break;
0883:
0884: default:
0885: throw new IOException("expected 'B' at " + (char) tag);
0886: }
0887: }
0888:
0889: while (length > 0) {
0890: if (_chunkLength > 0) {
0891: buffer[offset++] = (byte) read();
0892: _chunkLength--;
0893: length--;
0894: readLength++;
0895: } else if (_isLastChunk) {
0896: if (readLength == 0)
0897: return -1;
0898: else {
0899: _chunkLength = END_OF_DATA;
0900: return readLength;
0901: }
0902: } else {
0903: int tag = read();
0904:
0905: switch (tag) {
0906: case 'B':
0907: case 'b':
0908: _isLastChunk = tag == 'B';
0909: _chunkLength = (read() << 8) + read();
0910: break;
0911:
0912: default:
0913: throw new IOException("expected 'B' at "
0914: + (char) tag);
0915: }
0916: }
0917: }
0918:
0919: if (readLength == 0)
0920: return -1;
0921: else if (_chunkLength > 0 || !_isLastChunk)
0922: return readLength;
0923: else {
0924: _chunkLength = END_OF_DATA;
0925: return readLength;
0926: }
0927: }
0928:
0929: /**
0930: * Reads a fault.
0931: */
0932: private HashMap readFault() throws IOException {
0933: HashMap map = new HashMap();
0934:
0935: int code = read();
0936: for (; code > 0 && code != 'z'; code = read()) {
0937: _peek = code;
0938:
0939: Object key = readObject();
0940: Object value = readObject();
0941:
0942: if (key != null && value != null)
0943: map.put(key, value);
0944: }
0945:
0946: if (code != 'z')
0947: throw expect("fault", code);
0948:
0949: return map;
0950: }
0951:
0952: /**
0953: * Reads an object from the input stream with an expected type.
0954: */
0955: public Object readObject(Class cl) throws IOException {
0956: if (cl == null || cl == Object.class)
0957: return readObject();
0958:
0959: int tag = read();
0960:
0961: switch (tag) {
0962: case 'N':
0963: return null;
0964:
0965: case 'M': {
0966: String type = readType();
0967:
0968: // hessian/3386
0969: if ("".equals(type)) {
0970: Deserializer reader;
0971: reader = _serializerFactory.getDeserializer(cl);
0972:
0973: return reader.readMap(this );
0974: } else {
0975: Deserializer reader;
0976: reader = _serializerFactory.getObjectDeserializer(type);
0977:
0978: return reader.readMap(this );
0979: }
0980: }
0981:
0982: case 'V': {
0983: String type = readType();
0984: int length = readLength();
0985:
0986: Deserializer reader;
0987: reader = _serializerFactory.getObjectDeserializer(type);
0988:
0989: if (cl != reader.getType()
0990: && cl.isAssignableFrom(reader.getType()))
0991: return reader.readList(this , length);
0992:
0993: reader = _serializerFactory.getDeserializer(cl);
0994:
0995: Object v = reader.readList(this , length);
0996:
0997: return v;
0998: }
0999:
1000: case 'R': {
1001: int ref = parseInt();
1002:
1003: return _refs.get(ref);
1004: }
1005:
1006: case 'r': {
1007: String type = readType();
1008: String url = readString();
1009:
1010: return resolveRemote(type, url);
1011: }
1012: }
1013:
1014: _peek = tag;
1015:
1016: // hessian/332i vs hessian/3406
1017: //return readObject();
1018:
1019: Object value = _serializerFactory.getDeserializer(cl)
1020: .readObject(this );
1021:
1022: return value;
1023: }
1024:
1025: /**
1026: * Reads an arbitrary object from the input stream when the type
1027: * is unknown.
1028: */
1029: public Object readObject() throws IOException {
1030: int tag = read();
1031:
1032: switch (tag) {
1033: case 'N':
1034: return null;
1035:
1036: case 'T':
1037: return Boolean.valueOf(true);
1038:
1039: case 'F':
1040: return Boolean.valueOf(false);
1041:
1042: case 'I':
1043: return Integer.valueOf(parseInt());
1044:
1045: case 'L':
1046: return Long.valueOf(parseLong());
1047:
1048: case 'D':
1049: return Double.valueOf(parseDouble());
1050:
1051: case 'd':
1052: return new Date(parseLong());
1053:
1054: case 'x':
1055: case 'X': {
1056: _isLastChunk = tag == 'X';
1057: _chunkLength = (read() << 8) + read();
1058:
1059: return parseXML();
1060: }
1061:
1062: case 's':
1063: case 'S': {
1064: _isLastChunk = tag == 'S';
1065: _chunkLength = (read() << 8) + read();
1066:
1067: int data;
1068: _sbuf.setLength(0);
1069:
1070: while ((data = parseChar()) >= 0)
1071: _sbuf.append((char) data);
1072:
1073: return _sbuf.toString();
1074: }
1075:
1076: case 'b':
1077: case 'B': {
1078: _isLastChunk = tag == 'B';
1079: _chunkLength = (read() << 8) + read();
1080:
1081: int data;
1082: ByteArrayOutputStream bos = new ByteArrayOutputStream();
1083:
1084: while ((data = parseByte()) >= 0)
1085: bos.write(data);
1086:
1087: return bos.toByteArray();
1088: }
1089:
1090: case 'V': {
1091: String type = readType();
1092: int length = readLength();
1093:
1094: return _serializerFactory.readList(this , length, type);
1095: }
1096:
1097: case 'M': {
1098: String type = readType();
1099:
1100: return _serializerFactory.readMap(this , type);
1101: }
1102:
1103: case 'R': {
1104: int ref = parseInt();
1105:
1106: return _refs.get(ref);
1107: }
1108:
1109: case 'r': {
1110: String type = readType();
1111: String url = readString();
1112:
1113: return resolveRemote(type, url);
1114: }
1115:
1116: default:
1117: throw error("unknown code for readObject at "
1118: + codeName(tag));
1119: }
1120: }
1121:
1122: /**
1123: * Reads a remote object.
1124: */
1125: public Object readRemote() throws IOException {
1126: String type = readType();
1127: String url = readString();
1128:
1129: return resolveRemote(type, url);
1130: }
1131:
1132: /**
1133: * Reads a reference.
1134: */
1135: public Object readRef() throws IOException {
1136: return _refs.get(parseInt());
1137: }
1138:
1139: /**
1140: * Reads the start of a list.
1141: */
1142: public int readListStart() throws IOException {
1143: return read();
1144: }
1145:
1146: /**
1147: * Reads the start of a list.
1148: */
1149: public int readMapStart() throws IOException {
1150: return read();
1151: }
1152:
1153: /**
1154: * Returns true if this is the end of a list or a map.
1155: */
1156: public boolean isEnd() throws IOException {
1157: int code = read();
1158:
1159: _peek = code;
1160:
1161: return (code < 0 || code == 'z');
1162: }
1163:
1164: /**
1165: * Reads the end byte.
1166: */
1167: public void readEnd() throws IOException {
1168: int code = read();
1169:
1170: if (code != 'z')
1171: throw error("unknown code at " + codeName(code));
1172: }
1173:
1174: /**
1175: * Reads the end byte.
1176: */
1177: public void readMapEnd() throws IOException {
1178: int code = read();
1179:
1180: if (code != 'z')
1181: throw error("expected end of map ('z') at "
1182: + codeName(code));
1183: }
1184:
1185: /**
1186: * Reads the end byte.
1187: */
1188: public void readListEnd() throws IOException {
1189: int code = read();
1190:
1191: if (code != 'z')
1192: throw error("expected end of list ('z') at "
1193: + codeName(code));
1194: }
1195:
1196: /**
1197: * Adds a list/map reference.
1198: */
1199: public int addRef(Object ref) {
1200: if (_refs == null)
1201: _refs = new ArrayList();
1202:
1203: _refs.add(ref);
1204:
1205: return _refs.size() - 1;
1206: }
1207:
1208: /**
1209: * Adds a list/map reference.
1210: */
1211: public void setRef(int i, Object ref) {
1212: _refs.set(i, ref);
1213: }
1214:
1215: /**
1216: * Resets the references for streaming.
1217: */
1218: public void resetReferences() {
1219: if (_refs != null)
1220: _refs.clear();
1221: }
1222:
1223: /**
1224: * Resolves a remote object.
1225: */
1226: public Object resolveRemote(String type, String url)
1227: throws IOException {
1228: HessianRemoteResolver resolver = getRemoteResolver();
1229:
1230: if (resolver != null)
1231: return resolver.lookup(type, url);
1232: else
1233: return new HessianRemote(type, url);
1234: }
1235:
1236: /**
1237: * Parses a type from the stream.
1238: *
1239: * <pre>
1240: * t b16 b8
1241: * </pre>
1242: */
1243: public String readType() throws IOException {
1244: int code = read();
1245:
1246: if (code != 't') {
1247: _peek = code;
1248: return "";
1249: }
1250:
1251: _isLastChunk = true;
1252: _chunkLength = (read() << 8) + read();
1253:
1254: _sbuf.setLength(0);
1255: int ch;
1256: while ((ch = parseChar()) >= 0)
1257: _sbuf.append((char) ch);
1258:
1259: return _sbuf.toString();
1260: }
1261:
1262: /**
1263: * Parses the length for an array
1264: *
1265: * <pre>
1266: * l b32 b24 b16 b8
1267: * </pre>
1268: */
1269: public int readLength() throws IOException {
1270: int code = read();
1271:
1272: if (code != 'l') {
1273: _peek = code;
1274: return -1;
1275: }
1276:
1277: return parseInt();
1278: }
1279:
1280: /**
1281: * Parses a 32-bit integer value from the stream.
1282: *
1283: * <pre>
1284: * b32 b24 b16 b8
1285: * </pre>
1286: */
1287: private int parseInt() throws IOException {
1288: int b32 = read();
1289: int b24 = read();
1290: int b16 = read();
1291: int b8 = read();
1292:
1293: return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
1294: }
1295:
1296: /**
1297: * Parses a 64-bit long value from the stream.
1298: *
1299: * <pre>
1300: * b64 b56 b48 b40 b32 b24 b16 b8
1301: * </pre>
1302: */
1303: private long parseLong() throws IOException {
1304: long b64 = read();
1305: long b56 = read();
1306: long b48 = read();
1307: long b40 = read();
1308: long b32 = read();
1309: long b24 = read();
1310: long b16 = read();
1311: long b8 = read();
1312:
1313: return ((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32)
1314: + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8);
1315: }
1316:
1317: /**
1318: * Parses a 64-bit double value from the stream.
1319: *
1320: * <pre>
1321: * b64 b56 b48 b40 b32 b24 b16 b8
1322: * </pre>
1323: */
1324: private double parseDouble() throws IOException {
1325: long b64 = read();
1326: long b56 = read();
1327: long b48 = read();
1328: long b40 = read();
1329: long b32 = read();
1330: long b24 = read();
1331: long b16 = read();
1332: long b8 = read();
1333:
1334: long bits = ((b64 << 56) + (b56 << 48) + (b48 << 40)
1335: + (b40 << 32) + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8);
1336:
1337: return Double.longBitsToDouble(bits);
1338: }
1339:
1340: org.w3c.dom.Node parseXML() throws IOException {
1341: throw new UnsupportedOperationException();
1342: }
1343:
1344: /**
1345: * Reads a character from the underlying stream.
1346: */
1347: private int parseChar() throws IOException {
1348: while (_chunkLength <= 0) {
1349: if (_isLastChunk)
1350: return -1;
1351:
1352: int code = read();
1353:
1354: switch (code) {
1355: case 's':
1356: case 'x':
1357: _isLastChunk = false;
1358:
1359: _chunkLength = (read() << 8) + read();
1360: break;
1361:
1362: case 'S':
1363: case 'X':
1364: _isLastChunk = true;
1365:
1366: _chunkLength = (read() << 8) + read();
1367: break;
1368:
1369: default:
1370: throw expect("string", code);
1371: }
1372:
1373: }
1374:
1375: _chunkLength--;
1376:
1377: return parseUTF8Char();
1378: }
1379:
1380: /**
1381: * Parses a single UTF8 character.
1382: */
1383: private int parseUTF8Char() throws IOException {
1384: int ch = read();
1385:
1386: if (ch < 0x80)
1387: return ch;
1388: else if ((ch & 0xe0) == 0xc0) {
1389: int ch1 = read();
1390: int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
1391:
1392: return v;
1393: } else if ((ch & 0xf0) == 0xe0) {
1394: int ch1 = read();
1395: int ch2 = read();
1396: int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6)
1397: + (ch2 & 0x3f);
1398:
1399: return v;
1400: } else
1401: throw error("bad utf-8 encoding at " + codeName(ch));
1402: }
1403:
1404: /**
1405: * Reads a byte from the underlying stream.
1406: */
1407: private int parseByte() throws IOException {
1408: while (_chunkLength <= 0) {
1409: if (_isLastChunk) {
1410: return -1;
1411: }
1412:
1413: int code = read();
1414:
1415: switch (code) {
1416: case 'b':
1417: _isLastChunk = false;
1418:
1419: _chunkLength = (read() << 8) + read();
1420: break;
1421:
1422: case 'B':
1423: _isLastChunk = true;
1424:
1425: _chunkLength = (read() << 8) + read();
1426: break;
1427:
1428: default:
1429: throw expect("byte[]", code);
1430: }
1431: }
1432:
1433: _chunkLength--;
1434:
1435: return read();
1436: }
1437:
1438: /**
1439: * Reads bytes based on an input stream.
1440: */
1441: public InputStream readInputStream() throws IOException {
1442: int tag = read();
1443:
1444: switch (tag) {
1445: case 'N':
1446: return null;
1447:
1448: case 'B':
1449: case 'b':
1450: _isLastChunk = tag == 'B';
1451: _chunkLength = (read() << 8) + read();
1452: break;
1453:
1454: default:
1455: throw expect("inputStream", tag);
1456: }
1457:
1458: return new InputStream() {
1459: boolean _isClosed = false;
1460:
1461: public int read() throws IOException {
1462: if (_isClosed || _is == null)
1463: return -1;
1464:
1465: int ch = parseByte();
1466: if (ch < 0)
1467: _isClosed = true;
1468:
1469: return ch;
1470: }
1471:
1472: public int read(byte[] buffer, int offset, int length)
1473: throws IOException {
1474: if (_isClosed || _is == null)
1475: return -1;
1476:
1477: int len = HessianInput.this
1478: .read(buffer, offset, length);
1479: if (len < 0)
1480: _isClosed = true;
1481:
1482: return len;
1483: }
1484:
1485: public void close() throws IOException {
1486: while (read() >= 0) {
1487: }
1488:
1489: _isClosed = true;
1490: }
1491: };
1492: }
1493:
1494: /**
1495: * Reads bytes from the underlying stream.
1496: */
1497: int read(byte[] buffer, int offset, int length) throws IOException {
1498: int readLength = 0;
1499:
1500: while (length > 0) {
1501: while (_chunkLength <= 0) {
1502: if (_isLastChunk)
1503: return readLength == 0 ? -1 : readLength;
1504:
1505: int code = read();
1506:
1507: switch (code) {
1508: case 'b':
1509: _isLastChunk = false;
1510:
1511: _chunkLength = (read() << 8) + read();
1512: break;
1513:
1514: case 'B':
1515: _isLastChunk = true;
1516:
1517: _chunkLength = (read() << 8) + read();
1518: break;
1519:
1520: default:
1521: throw expect("byte[]", code);
1522: }
1523: }
1524:
1525: int sublen = _chunkLength;
1526: if (length < sublen)
1527: sublen = length;
1528:
1529: sublen = _is.read(buffer, offset, sublen);
1530: offset += sublen;
1531: readLength += sublen;
1532: length -= sublen;
1533: _chunkLength -= sublen;
1534: }
1535:
1536: return readLength;
1537: }
1538:
1539: final int read() throws IOException {
1540: if (_peek >= 0) {
1541: int value = _peek;
1542: _peek = -1;
1543: return value;
1544: }
1545:
1546: int ch = _is.read();
1547:
1548: return ch;
1549: }
1550:
1551: public void close() {
1552: _is = null;
1553: }
1554:
1555: public Reader getReader() {
1556: return null;
1557: }
1558:
1559: protected IOException expect(String expect, int ch) {
1560: return error("expected " + expect + " at " + codeName(ch));
1561: }
1562:
1563: protected String codeName(int ch) {
1564: if (ch < 0)
1565: return "end of file";
1566: else
1567: return "0x" + Integer.toHexString(ch & 0xff) + " ("
1568: + (char) +ch + ")";
1569: }
1570:
1571: protected IOException error(String message) {
1572: if (_method != null)
1573: return new HessianProtocolException(_method + ": "
1574: + message);
1575: else
1576: return new HessianProtocolException(message);
1577: }
1578:
1579: static {
1580: try {
1581: _detailMessageField = Throwable.class
1582: .getDeclaredField("detailMessage");
1583: _detailMessageField.setAccessible(true);
1584: } catch (Throwable e) {
1585: }
1586: }
1587: }
|