0001: /*
0002: * Copyright (c) 2001-2008 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.burlap.io;
0050:
0051: import com.caucho.hessian.io.Deserializer;
0052: import com.caucho.hessian.io.HessianRemoteResolver;
0053: import com.caucho.hessian.io.SerializerFactory;
0054:
0055: import java.io.ByteArrayOutputStream;
0056: import java.io.IOException;
0057: import java.io.InputStream;
0058: import java.io.Reader;
0059: import java.lang.reflect.Field;
0060: import java.util.ArrayList;
0061: import java.util.Calendar;
0062: import java.util.Date;
0063: import java.util.HashMap;
0064: import java.util.TimeZone;
0065:
0066: /**
0067: * Input stream for Burlap requests.
0068: *
0069: * <p>BurlapInput is unbuffered, so any client needs to provide
0070: * its own buffering.
0071: *
0072: * <pre>
0073: * InputStream is = ...; // from http connection
0074: * BurlapInput in = new BurlapInput(is);
0075: * String value;
0076: *
0077: * in.startReply(); // read reply header
0078: * value = in.readString(); // read string value
0079: * in.completeReply(); // read reply footer
0080: * </pre>
0081: */
0082: public class BurlapInput extends AbstractBurlapInput {
0083: private static int[] base64Decode;
0084:
0085: public final static int TAG_EOF = -1;
0086:
0087: public final static int TAG_NULL = 0;
0088: public final static int TAG_BOOLEAN = 1;
0089: public final static int TAG_INT = 2;
0090: public final static int TAG_LONG = 3;
0091: public final static int TAG_DOUBLE = 4;
0092: public final static int TAG_DATE = 5;
0093: public final static int TAG_STRING = 6;
0094: public final static int TAG_XML = 7;
0095: public final static int TAG_BASE64 = 8;
0096: public final static int TAG_MAP = 9;
0097: public final static int TAG_LIST = 10;
0098: public final static int TAG_TYPE = 11;
0099: public final static int TAG_LENGTH = 12;
0100:
0101: public final static int TAG_REF = 13;
0102: public final static int TAG_REMOTE = 14;
0103:
0104: public final static int TAG_CALL = 15;
0105: public final static int TAG_REPLY = 16;
0106: public final static int TAG_FAULT = 17;
0107: public final static int TAG_METHOD = 18;
0108: public final static int TAG_HEADER = 19;
0109:
0110: public final static int TAG_NULL_END = TAG_NULL + 100;
0111: public final static int TAG_BOOLEAN_END = TAG_BOOLEAN + 100;
0112: public final static int TAG_INT_END = TAG_INT + 100;
0113: public final static int TAG_LONG_END = TAG_LONG + 100;
0114: public final static int TAG_DOUBLE_END = TAG_DOUBLE + 100;
0115: public final static int TAG_DATE_END = TAG_DATE + 100;
0116: public final static int TAG_STRING_END = TAG_STRING + 100;
0117: public final static int TAG_XML_END = TAG_XML + 100;
0118: public final static int TAG_BASE64_END = TAG_BASE64 + 100;
0119: public final static int TAG_MAP_END = TAG_MAP + 100;
0120: public final static int TAG_LIST_END = TAG_LIST + 100;
0121: public final static int TAG_TYPE_END = TAG_TYPE + 100;
0122: public final static int TAG_LENGTH_END = TAG_LENGTH + 100;
0123:
0124: public final static int TAG_REF_END = TAG_REF + 100;
0125: public final static int TAG_REMOTE_END = TAG_REMOTE + 100;
0126:
0127: public final static int TAG_CALL_END = TAG_CALL + 100;
0128: public final static int TAG_REPLY_END = TAG_REPLY + 100;
0129: public final static int TAG_FAULT_END = TAG_FAULT + 100;
0130: public final static int TAG_METHOD_END = TAG_METHOD + 100;
0131: public final static int TAG_HEADER_END = TAG_HEADER + 100;
0132:
0133: private static HashMap _tagMap;
0134:
0135: private static Field _detailMessageField;
0136:
0137: protected SerializerFactory _serializerFactory;
0138:
0139: protected ArrayList _refs;
0140:
0141: // the underlying input stream
0142: private InputStream _is;
0143: // a peek character
0144: protected int _peek = -1;
0145:
0146: // the method for a call
0147: private String _method;
0148:
0149: private int _peekTag;
0150:
0151: private Throwable _replyFault;
0152:
0153: protected StringBuffer _sbuf = new StringBuffer();
0154: protected StringBuffer _entityBuffer = new StringBuffer();
0155:
0156: protected Calendar _utcCalendar;
0157: protected Calendar _localCalendar;
0158:
0159: /**
0160: * Creates an uninitialized Burlap input stream.
0161: */
0162: public BurlapInput() {
0163: }
0164:
0165: /**
0166: * Creates a new Burlap input stream, initialized with an
0167: * underlying input stream.
0168: *
0169: * @param is the underlying input stream.
0170: */
0171: public BurlapInput(InputStream is) {
0172: init(is);
0173: }
0174:
0175: /**
0176: * Sets the serializer factory.
0177: */
0178: public void setSerializerFactory(SerializerFactory factory) {
0179: _serializerFactory = factory;
0180: }
0181:
0182: /**
0183: * Gets the serializer factory.
0184: */
0185: public SerializerFactory getSerializerFactory() {
0186: return _serializerFactory;
0187: }
0188:
0189: /**
0190: * Initialize the burlap stream with the underlying input stream.
0191: */
0192: public void init(InputStream is) {
0193: _is = is;
0194: _method = null;
0195: _peek = -1;
0196: _peekTag = -1;
0197: _refs = null;
0198: _replyFault = null;
0199:
0200: if (_serializerFactory == null)
0201: _serializerFactory = new SerializerFactory();
0202: }
0203:
0204: /**
0205: * Returns the calls method
0206: */
0207: public String getMethod() {
0208: return _method;
0209: }
0210:
0211: /**
0212: * Returns any reply fault.
0213: */
0214: public Throwable getReplyFault() {
0215: return _replyFault;
0216: }
0217:
0218: /**
0219: * Starts reading the call
0220: *
0221: * <pre>
0222: * <burlap:call>
0223: * <method>method</method>
0224: * </pre>
0225: */
0226: public void startCall() throws IOException {
0227: readCall();
0228:
0229: while ((readHeader() != null))
0230: readObject();
0231:
0232: readMethod();
0233: }
0234:
0235: /**
0236: * Starts reading the call
0237: *
0238: * <p>A successful completion will have a single value:
0239: *
0240: * <pre>
0241: * <burlap:call>
0242: * </pre>
0243: */
0244: public int readCall() throws IOException {
0245: expectTag(TAG_CALL);
0246:
0247: int major = 1;
0248: int minor = 0;
0249:
0250: return (major << 16) + minor;
0251: }
0252:
0253: /**
0254: * Reads the method
0255: *
0256: * <pre>
0257: * <method>method</method>
0258: * </pre>
0259: */
0260: public String readMethod() throws IOException {
0261: expectTag(TAG_METHOD);
0262:
0263: _method = parseString();
0264:
0265: expectTag(TAG_METHOD_END);
0266:
0267: return _method;
0268: }
0269:
0270: /**
0271: * Completes reading the call
0272: *
0273: * <p>A successful completion will have a single value:
0274: *
0275: * <pre>
0276: * </burlap:call>
0277: * </pre>
0278: */
0279: public void completeCall() throws IOException {
0280: expectTag(TAG_CALL_END);
0281: }
0282:
0283: /**
0284: * Reads a reply as an object.
0285: * If the reply has a fault, throws the exception.
0286: */
0287: public Object readReply(Class expectedClass) throws Throwable {
0288: expectTag(TAG_REPLY);
0289:
0290: int tag = parseTag();
0291:
0292: if (tag == TAG_FAULT)
0293: throw prepareFault();
0294: else {
0295: _peekTag = tag;
0296: Object value = readObject(expectedClass);
0297:
0298: expectTag(TAG_REPLY_END);
0299:
0300: return value;
0301: }
0302: }
0303:
0304: /**
0305: * Starts reading the reply
0306: *
0307: * <p>A successful completion will have a single value:
0308: *
0309: * <pre>
0310: * <burlap:reply>
0311: * <value>
0312: * </pre>
0313: */
0314: public void startReply() throws Throwable {
0315: expectTag(TAG_REPLY);
0316:
0317: int tag = parseTag();
0318: if (tag == TAG_FAULT)
0319: throw prepareFault();
0320: else
0321: _peekTag = tag;
0322: }
0323:
0324: /**
0325: * Prepares the fault.
0326: */
0327: private Throwable prepareFault() throws IOException {
0328: HashMap fault = readFault();
0329:
0330: Object detail = fault.get("detail");
0331: String message = (String) fault.get("message");
0332:
0333: if (detail instanceof Throwable) {
0334: _replyFault = (Throwable) detail;
0335:
0336: if (message != null && _detailMessageField != null) {
0337: try {
0338: _detailMessageField.set(_replyFault, message);
0339: } catch (Throwable e) {
0340: }
0341: }
0342:
0343: return _replyFault;
0344: }
0345:
0346: else {
0347: String code = (String) fault.get("code");
0348:
0349: _replyFault = new BurlapServiceException(message, code,
0350: detail);
0351:
0352: return _replyFault;
0353: }
0354: }
0355:
0356: /**
0357: * Completes reading the call
0358: *
0359: * <p>A successful completion will have a single value:
0360: *
0361: * <pre>
0362: * </burlap:reply>
0363: * </pre>
0364: */
0365: public void completeReply() throws IOException {
0366: expectTag(TAG_REPLY_END);
0367: }
0368:
0369: /**
0370: * Reads a header, returning null if there are no headers.
0371: *
0372: * <pre>
0373: * <header>value</header>
0374: * </pre>
0375: */
0376: public String readHeader() throws IOException {
0377: int tag = parseTag();
0378:
0379: if (tag == TAG_HEADER) {
0380: _sbuf.setLength(0);
0381: String value = parseString(_sbuf).toString();
0382: expectTag(TAG_HEADER_END);
0383: return value;
0384: }
0385:
0386: _peekTag = tag;
0387:
0388: return null;
0389: }
0390:
0391: /**
0392: * Reads a null
0393: *
0394: * <pre>
0395: * <null></null>
0396: * </pre>
0397: */
0398: public void readNull() throws IOException {
0399: int tag = parseTag();
0400:
0401: switch (tag) {
0402: case TAG_NULL:
0403: expectTag(TAG_NULL_END);
0404: return;
0405:
0406: default:
0407: throw expectedTag("null", tag);
0408: }
0409: }
0410:
0411: /**
0412: * Reads a boolean
0413: *
0414: * <pre>
0415: * <boolean>0</boolean>
0416: * <boolean>1</boolean>
0417: * </pre>
0418: */
0419: public boolean readBoolean() throws IOException {
0420: int tag = parseTag();
0421:
0422: boolean value;
0423:
0424: switch (tag) {
0425: case TAG_NULL:
0426: value = false;
0427: expectTag(TAG_NULL_END);
0428: return value;
0429:
0430: case TAG_BOOLEAN:
0431: value = parseInt() != 0;
0432: expectTag(TAG_BOOLEAN_END);
0433: return value;
0434:
0435: case TAG_INT:
0436: value = parseInt() != 0;
0437: expectTag(TAG_INT_END);
0438: return value;
0439:
0440: case TAG_LONG:
0441: value = parseLong() != 0;
0442: expectTag(TAG_LONG_END);
0443: return value;
0444:
0445: case TAG_DOUBLE:
0446: value = parseDouble() != 0;
0447: expectTag(TAG_DOUBLE_END);
0448: return value;
0449:
0450: default:
0451: throw expectedTag("boolean", tag);
0452: }
0453: }
0454:
0455: /**
0456: * Reads a byte
0457: *
0458: * <pre>
0459: * <int>value</int>
0460: * </pre>
0461: */
0462: public byte readByte() throws IOException {
0463: return (byte) readInt();
0464: }
0465:
0466: /**
0467: * Reads a short
0468: *
0469: * <pre>
0470: * <int>value</int>
0471: * </pre>
0472: */
0473: public short readShort() throws IOException {
0474: return (short) readInt();
0475: }
0476:
0477: /**
0478: * Reads an integer
0479: *
0480: * <pre>
0481: * <int>value</int>
0482: * </pre>
0483: */
0484: public int readInt() throws IOException {
0485: int tag = parseTag();
0486:
0487: int value;
0488:
0489: switch (tag) {
0490: case TAG_NULL:
0491: value = 0;
0492: expectTag(TAG_NULL_END);
0493: return value;
0494:
0495: case TAG_BOOLEAN:
0496: value = parseInt();
0497: expectTag(TAG_BOOLEAN_END);
0498: return value;
0499:
0500: case TAG_INT:
0501: value = parseInt();
0502: expectTag(TAG_INT_END);
0503: return value;
0504:
0505: case TAG_LONG:
0506: value = (int) parseLong();
0507: expectTag(TAG_LONG_END);
0508: return value;
0509:
0510: case TAG_DOUBLE:
0511: value = (int) parseDouble();
0512: expectTag(TAG_DOUBLE_END);
0513: return value;
0514:
0515: default:
0516: throw expectedTag("int", tag);
0517: }
0518: }
0519:
0520: /**
0521: * Reads a long
0522: *
0523: * <pre>
0524: * <long>value</long>
0525: * </pre>
0526: */
0527: public long readLong() throws IOException {
0528: int tag = parseTag();
0529:
0530: long value;
0531:
0532: switch (tag) {
0533: case TAG_NULL:
0534: value = 0;
0535: expectTag(TAG_NULL_END);
0536: return value;
0537:
0538: case TAG_BOOLEAN:
0539: value = parseInt();
0540: expectTag(TAG_BOOLEAN_END);
0541: return value;
0542:
0543: case TAG_INT:
0544: value = parseInt();
0545: expectTag(TAG_INT_END);
0546: return value;
0547:
0548: case TAG_LONG:
0549: value = parseLong();
0550: expectTag(TAG_LONG_END);
0551: return value;
0552:
0553: case TAG_DOUBLE:
0554: value = (long) parseDouble();
0555: expectTag(TAG_DOUBLE_END);
0556: return value;
0557:
0558: default:
0559: throw expectedTag("long", tag);
0560: }
0561: }
0562:
0563: /**
0564: * Reads a float
0565: *
0566: * <pre>
0567: * <double>value</double>
0568: * </pre>
0569: */
0570: public float readFloat() throws IOException {
0571: return (float) readDouble();
0572: }
0573:
0574: /**
0575: * Reads a double
0576: *
0577: * <pre>
0578: * <double>value</double>
0579: * </pre>
0580: */
0581: public double readDouble() throws IOException {
0582: int tag = parseTag();
0583:
0584: double value;
0585:
0586: switch (tag) {
0587: case TAG_NULL:
0588: value = 0;
0589: expectTag(TAG_NULL_END);
0590: return value;
0591:
0592: case TAG_BOOLEAN:
0593: value = parseInt();
0594: expectTag(TAG_BOOLEAN_END);
0595: return value;
0596:
0597: case TAG_INT:
0598: value = parseInt();
0599: expectTag(TAG_INT_END);
0600: return value;
0601:
0602: case TAG_LONG:
0603: value = parseLong();
0604: expectTag(TAG_LONG_END);
0605: return value;
0606:
0607: case TAG_DOUBLE:
0608: value = parseDouble();
0609: expectTag(TAG_DOUBLE_END);
0610: return value;
0611:
0612: default:
0613: throw expectedTag("double", tag);
0614: }
0615: }
0616:
0617: /**
0618: * Reads a date.
0619: *
0620: * <pre>
0621: * <date>ISO-8609 date</date>
0622: * </pre>
0623: */
0624: public long readUTCDate() throws IOException {
0625: int tag = parseTag();
0626:
0627: if (tag != TAG_DATE)
0628: throw error("expected date");
0629:
0630: if (_utcCalendar == null)
0631: _utcCalendar = Calendar.getInstance(TimeZone
0632: .getTimeZone("UTC"));
0633:
0634: long value = parseDate(_utcCalendar);
0635:
0636: expectTag(TAG_DATE_END);
0637:
0638: return value;
0639: }
0640:
0641: /**
0642: * Reads a date.
0643: *
0644: * <pre>
0645: * <date>ISO-8609 date</date>
0646: * </pre>
0647: */
0648: public long readLocalDate() throws IOException {
0649: int tag = parseTag();
0650:
0651: if (tag != TAG_DATE)
0652: throw error("expected date");
0653:
0654: if (_localCalendar == null)
0655: _localCalendar = Calendar.getInstance();
0656:
0657: long value = parseDate(_localCalendar);
0658:
0659: expectTag(TAG_DATE_END);
0660:
0661: return value;
0662: }
0663:
0664: /**
0665: * Reads a string
0666: *
0667: * <pre>
0668: * <string>value</string>
0669: * </pre>
0670: */
0671: public String readString() throws IOException {
0672: int tag = parseTag();
0673:
0674: String value;
0675:
0676: switch (tag) {
0677: case TAG_NULL:
0678: expectTag(TAG_NULL_END);
0679: return null;
0680:
0681: case TAG_STRING:
0682: _sbuf.setLength(0);
0683: value = parseString(_sbuf).toString();
0684: expectTag(TAG_STRING_END);
0685: return value;
0686:
0687: case TAG_XML:
0688: _sbuf.setLength(0);
0689: value = parseString(_sbuf).toString();
0690: expectTag(TAG_XML_END);
0691: return value;
0692:
0693: default:
0694: throw expectedTag("string", tag);
0695: }
0696: }
0697:
0698: /**
0699: * Reads an XML node.
0700: *
0701: * <pre>
0702: * &xml;xml string</xml>
0703: * </pre>
0704: */
0705: public org.w3c.dom.Node readNode() throws IOException {
0706: int tag = read();
0707:
0708: switch (tag) {
0709: case 'N':
0710: return null;
0711:
0712: case 'S':
0713: case 's':
0714: case 'X':
0715: case 'x':
0716: throw error("can't cope");
0717:
0718: default:
0719: throw expectedTag("string", tag);
0720: }
0721: }
0722:
0723: /**
0724: * Reads a byte array
0725: *
0726: * <pre>
0727: * <base64>...</base64>
0728: * </pre>
0729: */
0730: public byte[] readBytes() throws IOException {
0731: int tag = parseTag();
0732:
0733: switch (tag) {
0734: case TAG_NULL:
0735: expectTag(TAG_NULL_END);
0736: return null;
0737:
0738: case TAG_BASE64:
0739: byte[] data = parseBytes();
0740: expectTag(TAG_BASE64_END);
0741:
0742: return data;
0743:
0744: default:
0745: throw expectedTag("bytes", tag);
0746: }
0747: }
0748:
0749: /**
0750: * Reads a length
0751: *
0752: * <pre>
0753: * <length>value</length>
0754: * </pre>
0755: */
0756: public int readLength() throws IOException {
0757: int tag = parseTag();
0758:
0759: if (tag != TAG_LENGTH) {
0760: _peekTag = tag;
0761: return -1;
0762: }
0763:
0764: int value = parseInt();
0765:
0766: expectTag(TAG_LENGTH_END);
0767:
0768: return value;
0769: }
0770:
0771: /**
0772: * Reads a fault.
0773: */
0774: private HashMap readFault() throws IOException {
0775: HashMap map = new HashMap();
0776:
0777: int code = parseTag();
0778: for (; code >= 0 && code != TAG_FAULT_END; code = parseTag()) {
0779: _peekTag = code;
0780:
0781: Object key = readObject();
0782: Object value = readObject();
0783:
0784: if (key != null && value != null)
0785: map.put(key, value);
0786: }
0787:
0788: if (code != TAG_FAULT_END)
0789: throw expectedTag("fault", code);
0790:
0791: return map;
0792: }
0793:
0794: /**
0795: * Reads an object from the input stream with an expected type.
0796: */
0797: public Object readObject(Class cl) throws IOException {
0798: if (cl == null || cl.equals(Object.class))
0799: return readObject();
0800:
0801: int tag = parseTag();
0802:
0803: switch (tag) {
0804: case TAG_NULL:
0805: expectTag(TAG_NULL_END);
0806: return null;
0807:
0808: case TAG_MAP: {
0809: String type = readType();
0810: Deserializer reader;
0811:
0812: reader = _serializerFactory.getObjectDeserializer(type, cl);
0813:
0814: return reader.readMap(this );
0815: }
0816:
0817: case TAG_LIST: {
0818: String type = readType();
0819: int length = readLength();
0820:
0821: Deserializer reader;
0822: reader = _serializerFactory.getObjectDeserializer(type, cl);
0823:
0824: return reader.readList(this , length);
0825: }
0826:
0827: case TAG_REF: {
0828: int ref = parseInt();
0829:
0830: expectTag(TAG_REF_END);
0831:
0832: return _refs.get(ref);
0833: }
0834:
0835: case TAG_REMOTE: {
0836: String type = readType();
0837: String url = readString();
0838:
0839: expectTag(TAG_REMOTE_END);
0840:
0841: Object remote = resolveRemote(type, url);
0842:
0843: return remote;
0844: }
0845: }
0846:
0847: _peekTag = tag;
0848:
0849: Object value = _serializerFactory.getDeserializer(cl)
0850: .readObject(this );
0851:
0852: return value;
0853: }
0854:
0855: /**
0856: * Reads an arbitrary object from the input stream when the type
0857: * is unknown.
0858: */
0859: public Object readObject() throws IOException {
0860: int tag = parseTag();
0861:
0862: switch (tag) {
0863: case TAG_NULL:
0864: expectTag(TAG_NULL_END);
0865: return null;
0866:
0867: case TAG_BOOLEAN: {
0868: int value = parseInt();
0869: expectTag(TAG_BOOLEAN_END);
0870: return new Boolean(value != 0);
0871: }
0872:
0873: case TAG_INT: {
0874: int value = parseInt();
0875: expectTag(TAG_INT_END);
0876: return new Integer(value);
0877: }
0878:
0879: case TAG_LONG: {
0880: long value = parseLong();
0881: expectTag(TAG_LONG_END);
0882: return new Long(value);
0883: }
0884:
0885: case TAG_DOUBLE: {
0886: double value = parseDouble();
0887: expectTag(TAG_DOUBLE_END);
0888: return new Double(value);
0889: }
0890:
0891: case TAG_DATE: {
0892: long value = parseDate();
0893: expectTag(TAG_DATE_END);
0894: return new Date(value);
0895: }
0896:
0897: case TAG_XML: {
0898: return parseXML();
0899: }
0900:
0901: case TAG_STRING: {
0902: _sbuf.setLength(0);
0903:
0904: String value = parseString(_sbuf).toString();
0905:
0906: expectTag(TAG_STRING_END);
0907:
0908: return value;
0909: }
0910:
0911: case TAG_BASE64: {
0912: byte[] data = parseBytes();
0913:
0914: expectTag(TAG_BASE64_END);
0915:
0916: return data;
0917: }
0918:
0919: case TAG_LIST: {
0920: String type = readType();
0921: int length = readLength();
0922:
0923: return _serializerFactory.readList(this , length, type);
0924: }
0925:
0926: case TAG_MAP: {
0927: String type = readType();
0928: Deserializer deserializer;
0929: deserializer = _serializerFactory
0930: .getObjectDeserializer(type);
0931:
0932: return deserializer.readMap(this );
0933: }
0934:
0935: case TAG_REF: {
0936: int ref = parseInt();
0937:
0938: expectTag(TAG_REF_END);
0939:
0940: return _refs.get(ref);
0941: }
0942:
0943: case TAG_REMOTE: {
0944: String type = readType();
0945: String url = readString();
0946:
0947: expectTag(TAG_REMOTE_END);
0948:
0949: return resolveRemote(type, url);
0950: }
0951:
0952: default:
0953: throw error("unknown code:" + tagName(tag));
0954: }
0955: }
0956:
0957: /**
0958: * Reads a remote object.
0959: */
0960: public Object readRemote() throws IOException {
0961: String type = readType();
0962: String url = readString();
0963:
0964: return resolveRemote(type, url);
0965: }
0966:
0967: /**
0968: * Reads a reference.
0969: */
0970: public Object readRef() throws IOException {
0971: return _refs.get(parseInt());
0972: }
0973:
0974: /**
0975: * Reads the start of a list.
0976: */
0977: public int readListStart() throws IOException {
0978: return parseTag();
0979: }
0980:
0981: /**
0982: * Reads the start of a map.
0983: */
0984: public int readMapStart() throws IOException {
0985: return parseTag();
0986: }
0987:
0988: /**
0989: * Returns true if this is the end of a list or a map.
0990: */
0991: public boolean isEnd() throws IOException {
0992: int code = parseTag();
0993:
0994: _peekTag = code;
0995:
0996: return (code < 0 || code >= 100);
0997: }
0998:
0999: /**
1000: * Reads the end byte.
1001: */
1002: public void readEnd() throws IOException {
1003: int code = parseTag();
1004:
1005: if (code < 100)
1006: throw error("unknown code:" + (char) code);
1007: }
1008:
1009: /**
1010: * Reads the end of the map
1011: */
1012: public void readMapEnd() throws IOException {
1013: expectTag(TAG_MAP_END);
1014: }
1015:
1016: /**
1017: * Reads the end of the map
1018: */
1019: public void readListEnd() throws IOException {
1020: expectTag(TAG_LIST_END);
1021: }
1022:
1023: /**
1024: * Adds a list/map reference.
1025: */
1026: public int addRef(Object ref) {
1027: if (_refs == null)
1028: _refs = new ArrayList();
1029:
1030: _refs.add(ref);
1031:
1032: return _refs.size() - 1;
1033: }
1034:
1035: /**
1036: * Adds a list/map reference.
1037: */
1038: public void setRef(int i, Object ref) {
1039: _refs.set(i, ref);
1040: }
1041:
1042: /**
1043: * Resolves a remote object.
1044: */
1045: public Object resolveRemote(String type, String url)
1046: throws IOException {
1047: HessianRemoteResolver resolver = getRemoteResolver();
1048:
1049: if (resolver != null)
1050: return resolver.lookup(type, url);
1051: else
1052: return new BurlapRemote(type, url);
1053: }
1054:
1055: /**
1056: * Parses a type from the stream.
1057: *
1058: * <pre>
1059: * <type>type</type>
1060: * </pre>
1061: */
1062: public String readType() throws IOException {
1063: int code = parseTag();
1064:
1065: if (code != TAG_TYPE) {
1066: _peekTag = code;
1067: return "";
1068: }
1069:
1070: _sbuf.setLength(0);
1071: int ch;
1072: while ((ch = readChar()) >= 0)
1073: _sbuf.append((char) ch);
1074: String type = _sbuf.toString();
1075:
1076: expectTag(TAG_TYPE_END);
1077:
1078: return type;
1079: }
1080:
1081: /**
1082: * Parses a 32-bit integer value from the stream.
1083: */
1084: private int parseInt() throws IOException {
1085: int sign = 1;
1086:
1087: int ch = read();
1088: if (ch == '-') {
1089: sign = -1;
1090: ch = read();
1091: }
1092:
1093: int value = 0;
1094: for (; ch >= '0' && ch <= '9'; ch = read())
1095: value = 10 * value + ch - '0';
1096:
1097: _peek = ch;
1098:
1099: return sign * value;
1100: }
1101:
1102: /**
1103: * Parses a 64-bit long value from the stream.
1104: */
1105: private long parseLong() throws IOException {
1106: int sign = 1;
1107:
1108: int ch = read();
1109: if (ch == '-') {
1110: sign = -1;
1111: ch = read();
1112: }
1113:
1114: long value = 0;
1115: for (; ch >= '0' && ch <= '9'; ch = read())
1116: value = 10 * value + ch - '0';
1117:
1118: _peek = ch;
1119:
1120: return sign * value;
1121: }
1122:
1123: /**
1124: * Parses a 64-bit double value from the stream.
1125: *
1126: * <pre>
1127: * b64 b56 b48 b40 b32 b24 b16 b8
1128: * </pre>
1129: */
1130: private double parseDouble() throws IOException {
1131: int ch = skipWhitespace();
1132:
1133: _sbuf.setLength(0);
1134:
1135: for (; !isWhitespace(ch) && ch != '<'; ch = read())
1136: _sbuf.append((char) ch);
1137:
1138: _peek = ch;
1139:
1140: return new Double(_sbuf.toString()).doubleValue();
1141: }
1142:
1143: /**
1144: * Parses a date value from the stream.
1145: */
1146: protected long parseDate() throws IOException {
1147: if (_utcCalendar == null)
1148: _utcCalendar = Calendar.getInstance(TimeZone
1149: .getTimeZone("UTC"));
1150:
1151: return parseDate(_utcCalendar);
1152: }
1153:
1154: /**
1155: * Parses a date value from the stream.
1156: */
1157: protected long parseDate(Calendar calendar) throws IOException {
1158: int ch = skipWhitespace();
1159:
1160: int year = 0;
1161: for (int i = 0; i < 4; i++) {
1162: if (ch >= '0' && ch <= '9')
1163: year = 10 * year + ch - '0';
1164: else
1165: throw expectedChar("year", ch);
1166:
1167: ch = read();
1168: }
1169:
1170: int month = 0;
1171: for (int i = 0; i < 2; i++) {
1172: if (ch >= '0' && ch <= '9')
1173: month = 10 * month + ch - '0';
1174: else
1175: throw expectedChar("month", ch);
1176:
1177: ch = read();
1178: }
1179:
1180: int day = 0;
1181: for (int i = 0; i < 2; i++) {
1182: if (ch >= '0' && ch <= '9')
1183: day = 10 * day + ch - '0';
1184: else
1185: throw expectedChar("day", ch);
1186:
1187: ch = read();
1188: }
1189:
1190: if (ch != 'T')
1191: throw expectedChar("`T'", ch);
1192:
1193: ch = read();
1194:
1195: int hour = 0;
1196: for (int i = 0; i < 2; i++) {
1197: if (ch >= '0' && ch <= '9')
1198: hour = 10 * hour + ch - '0';
1199: else
1200: throw expectedChar("hour", ch);
1201:
1202: ch = read();
1203: }
1204:
1205: int minute = 0;
1206: for (int i = 0; i < 2; i++) {
1207: if (ch >= '0' && ch <= '9')
1208: minute = 10 * minute + ch - '0';
1209: else
1210: throw expectedChar("minute", ch);
1211:
1212: ch = read();
1213: }
1214:
1215: int second = 0;
1216: for (int i = 0; i < 2; i++) {
1217: if (ch >= '0' && ch <= '9')
1218: second = 10 * second + ch - '0';
1219: else
1220: throw expectedChar("second", ch);
1221:
1222: ch = read();
1223: }
1224:
1225: int ms = 0;
1226: if (ch == '.') {
1227: ch = read();
1228:
1229: while (ch >= '0' && ch <= '9') {
1230: ms = 10 * ms + ch - '0';
1231:
1232: ch = read();
1233: }
1234: }
1235:
1236: for (; ch > 0 && ch != '<'; ch = read()) {
1237: }
1238:
1239: _peek = ch;
1240:
1241: calendar.set(Calendar.YEAR, year);
1242: calendar.set(Calendar.MONTH, month - 1);
1243: calendar.set(Calendar.DAY_OF_MONTH, day);
1244: calendar.set(Calendar.HOUR_OF_DAY, hour);
1245: calendar.set(Calendar.MINUTE, minute);
1246: calendar.set(Calendar.SECOND, second);
1247: calendar.set(Calendar.MILLISECOND, ms);
1248:
1249: return calendar.getTime().getTime();
1250: }
1251:
1252: protected String parseString() throws IOException {
1253: _sbuf.setLength(0);
1254:
1255: return parseString(_sbuf).toString();
1256: }
1257:
1258: /**
1259: * Parses a string value from the stream. The burlap object's
1260: * string buffer is used for the result.
1261: */
1262: protected StringBuffer parseString(StringBuffer sbuf)
1263: throws IOException {
1264: int ch;
1265:
1266: while ((ch = readChar()) >= 0)
1267: sbuf.append((char) ch);
1268:
1269: return sbuf;
1270: }
1271:
1272: org.w3c.dom.Node parseXML() throws IOException {
1273: throw error("help!");
1274: }
1275:
1276: /**
1277: * Reads a character from the underlying stream.
1278: */
1279: int readChar() throws IOException {
1280: int ch = read();
1281:
1282: if (ch == '<' || ch < 0) {
1283: _peek = ch;
1284: return -1;
1285: }
1286:
1287: if (ch == '&') {
1288: ch = read();
1289:
1290: if (ch == '#') {
1291: ch = read();
1292:
1293: if (ch >= '0' && ch <= '9') {
1294: int v = 0;
1295: for (; ch >= '0' && ch <= '9'; ch = read()) {
1296: v = 10 * v + ch - '0';
1297: }
1298:
1299: if (ch != ';')
1300: throw error("expected ';' at " + (char) ch);
1301:
1302: return (char) v;
1303: } else
1304: throw error("expected digit at " + (char) ch);
1305: } else {
1306: _entityBuffer.setLength(0);
1307:
1308: for (; ch >= 'a' && ch <= 'z'; ch = read())
1309: _entityBuffer.append((char) ch);
1310:
1311: String entity = _entityBuffer.toString();
1312:
1313: if (ch != ';')
1314: throw expectedChar("';'", ch);
1315:
1316: if (entity.equals("amp"))
1317: return '&';
1318: else if (entity.equals("apos"))
1319: return '\'';
1320: else if (entity.equals("quot"))
1321: return '"';
1322: else if (entity.equals("lt"))
1323: return '<';
1324: else if (entity.equals("gt"))
1325: return '>';
1326: else
1327: throw new BurlapProtocolException(
1328: "unknown XML entity &" + entity + "; at `"
1329: + (char) ch + "'");
1330: }
1331: } else if (ch < 0x80)
1332: return (char) ch;
1333: else if ((ch & 0xe0) == 0xc0) {
1334: int ch1 = read();
1335: int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
1336:
1337: return (char) v;
1338: } else if ((ch & 0xf0) == 0xe0) {
1339: int ch1 = read();
1340: int ch2 = read();
1341: int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6)
1342: + (ch2 & 0x3f);
1343:
1344: return (char) v;
1345: } else
1346: throw new BurlapProtocolException("bad utf-8 encoding");
1347: }
1348:
1349: /**
1350: * Parses a byte array.
1351: */
1352: protected byte[] parseBytes() throws IOException {
1353: ByteArrayOutputStream bos = new ByteArrayOutputStream();
1354:
1355: parseBytes(bos);
1356:
1357: return bos.toByteArray();
1358: }
1359:
1360: /**
1361: * Parses a byte array.
1362: */
1363: protected ByteArrayOutputStream parseBytes(ByteArrayOutputStream bos)
1364: throws IOException {
1365: int ch;
1366: for (ch = skipWhitespace(); ch >= 0 && ch != '<'; ch = skipWhitespace()) {
1367: int b1 = ch;
1368: int b2 = read();
1369: int b3 = read();
1370: int b4 = read();
1371:
1372: if (b4 != '=') {
1373: int chunk = ((base64Decode[b1] << 18)
1374: + (base64Decode[b2] << 12)
1375: + (base64Decode[b3] << 6) + (base64Decode[b4]));
1376:
1377: bos.write(chunk >> 16);
1378: bos.write(chunk >> 8);
1379: bos.write(chunk);
1380: } else if (b3 != '=') {
1381: int chunk = ((base64Decode[b1] << 10)
1382: + (base64Decode[b2] << 4) + (base64Decode[b3] >> 2));
1383:
1384: bos.write(chunk >> 8);
1385: bos.write(chunk);
1386: } else {
1387: int chunk = ((base64Decode[b1] << 2) + (base64Decode[b2] >> 4));
1388:
1389: bos.write(chunk);
1390: }
1391: }
1392:
1393: if (ch == '<')
1394: _peek = ch;
1395:
1396: return bos;
1397: }
1398:
1399: public void expectTag(int expectTag) throws IOException {
1400: int tag = parseTag();
1401:
1402: if (tag != expectTag)
1403: throw error("expected " + tagName(expectTag) + " at "
1404: + tagName(tag));
1405: }
1406:
1407: /**
1408: * Parses a tag. Returns true if it's a start tag.
1409: */
1410: protected int parseTag() throws IOException {
1411: if (_peekTag >= 0) {
1412: int tag = _peekTag;
1413: _peekTag = -1;
1414: return tag;
1415: }
1416:
1417: int ch = skipWhitespace();
1418: int endTagDelta = 0;
1419:
1420: if (ch != '<')
1421: throw expectedChar("'<'", ch);
1422:
1423: ch = read();
1424: if (ch == '/') {
1425: endTagDelta = 100;
1426: ch = _is.read();
1427: }
1428:
1429: if (!isTagChar(ch))
1430: throw expectedChar("tag", ch);
1431:
1432: _sbuf.setLength(0);
1433: for (; isTagChar(ch); ch = read())
1434: _sbuf.append((char) ch);
1435:
1436: if (ch != '>')
1437: throw expectedChar("'>'", ch);
1438:
1439: Integer value = (Integer) _tagMap.get(_sbuf.toString());
1440: if (value == null)
1441: throw error("Unknown tag <" + _sbuf + ">");
1442:
1443: return value.intValue() + endTagDelta;
1444: }
1445:
1446: /**
1447: * Returns true if the character is a valid tag character.
1448: */
1449: private boolean isTagChar(int ch) {
1450: return (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'
1451: || ch >= '0' && ch <= '9' || ch == ':' || ch == '-');
1452: }
1453:
1454: protected int skipWhitespace() throws IOException {
1455: int ch = read();
1456:
1457: for (; ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; ch = read()) {
1458: }
1459:
1460: return ch;
1461: }
1462:
1463: protected boolean isWhitespace(int ch) throws IOException {
1464: return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
1465: }
1466:
1467: /**
1468: * Reads bytes from the underlying stream.
1469: */
1470: int read(byte[] buffer, int offset, int length) throws IOException {
1471: throw new UnsupportedOperationException();
1472: }
1473:
1474: int read() throws IOException {
1475: if (_peek >= 0) {
1476: int value = _peek;
1477: _peek = -1;
1478: return value;
1479: }
1480:
1481: int ch = _is.read();
1482: return ch;
1483: }
1484:
1485: public Reader getReader() {
1486: return null;
1487: }
1488:
1489: public InputStream readInputStream() {
1490: return null;
1491: }
1492:
1493: public InputStream getInputStream() {
1494: return null;
1495: }
1496:
1497: protected IOException expectBeginTag(String expect, String tag) {
1498: return new BurlapProtocolException("expected <" + expect
1499: + "> at <" + tag + ">");
1500: }
1501:
1502: protected IOException expectedChar(String expect, int ch) {
1503: if (ch < 0)
1504: return error("expected " + expect + " at end of file");
1505: else
1506: return error("expected " + expect + " at " + (char) ch);
1507: }
1508:
1509: protected IOException expectedTag(String expect, int tag) {
1510: return error("expected " + expect + " at " + tagName(tag));
1511: }
1512:
1513: protected IOException error(String message) {
1514: return new BurlapProtocolException(message);
1515: }
1516:
1517: protected static String tagName(int tag) {
1518: switch (tag) {
1519: case TAG_NULL:
1520: return "<null>";
1521: case TAG_NULL_END:
1522: return "</null>";
1523:
1524: case TAG_BOOLEAN:
1525: return "<boolean>";
1526: case TAG_BOOLEAN_END:
1527: return "</boolean>";
1528:
1529: case TAG_INT:
1530: return "<int>";
1531: case TAG_INT_END:
1532: return "</int>";
1533:
1534: case TAG_LONG:
1535: return "<long>";
1536: case TAG_LONG_END:
1537: return "</long>";
1538:
1539: case TAG_DOUBLE:
1540: return "<double>";
1541: case TAG_DOUBLE_END:
1542: return "</double>";
1543:
1544: case TAG_STRING:
1545: return "<string>";
1546: case TAG_STRING_END:
1547: return "</string>";
1548:
1549: case TAG_XML:
1550: return "<xml>";
1551: case TAG_XML_END:
1552: return "</xml>";
1553:
1554: case TAG_BASE64:
1555: return "<base64>";
1556: case TAG_BASE64_END:
1557: return "</base64>";
1558:
1559: case TAG_MAP:
1560: return "<map>";
1561: case TAG_MAP_END:
1562: return "</map>";
1563:
1564: case TAG_LIST:
1565: return "<list>";
1566: case TAG_LIST_END:
1567: return "</list>";
1568:
1569: case TAG_TYPE:
1570: return "<type>";
1571: case TAG_TYPE_END:
1572: return "</type>";
1573:
1574: case TAG_LENGTH:
1575: return "<length>";
1576: case TAG_LENGTH_END:
1577: return "</length>";
1578:
1579: case TAG_REF:
1580: return "<ref>";
1581: case TAG_REF_END:
1582: return "</ref>";
1583:
1584: case TAG_REMOTE:
1585: return "<remote>";
1586: case TAG_REMOTE_END:
1587: return "</remote>";
1588:
1589: case TAG_CALL:
1590: return "<burlap:call>";
1591: case TAG_CALL_END:
1592: return "</burlap:call>";
1593:
1594: case TAG_REPLY:
1595: return "<burlap:reply>";
1596: case TAG_REPLY_END:
1597: return "</burlap:reply>";
1598:
1599: case TAG_HEADER:
1600: return "<header>";
1601: case TAG_HEADER_END:
1602: return "</header>";
1603:
1604: case TAG_FAULT:
1605: return "<fault>";
1606: case TAG_FAULT_END:
1607: return "</fault>";
1608:
1609: case -1:
1610: return "end of file";
1611:
1612: default:
1613: return "unknown " + tag;
1614: }
1615: }
1616:
1617: static {
1618: _tagMap = new HashMap();
1619: _tagMap.put("null", new Integer(TAG_NULL));
1620:
1621: _tagMap.put("boolean", new Integer(TAG_BOOLEAN));
1622: _tagMap.put("int", new Integer(TAG_INT));
1623: _tagMap.put("long", new Integer(TAG_LONG));
1624: _tagMap.put("double", new Integer(TAG_DOUBLE));
1625:
1626: _tagMap.put("date", new Integer(TAG_DATE));
1627:
1628: _tagMap.put("string", new Integer(TAG_STRING));
1629: _tagMap.put("xml", new Integer(TAG_XML));
1630: _tagMap.put("base64", new Integer(TAG_BASE64));
1631:
1632: _tagMap.put("map", new Integer(TAG_MAP));
1633: _tagMap.put("list", new Integer(TAG_LIST));
1634:
1635: _tagMap.put("type", new Integer(TAG_TYPE));
1636: _tagMap.put("length", new Integer(TAG_LENGTH));
1637:
1638: _tagMap.put("ref", new Integer(TAG_REF));
1639: _tagMap.put("remote", new Integer(TAG_REMOTE));
1640:
1641: _tagMap.put("burlap:call", new Integer(TAG_CALL));
1642: _tagMap.put("burlap:reply", new Integer(TAG_REPLY));
1643: _tagMap.put("fault", new Integer(TAG_FAULT));
1644: _tagMap.put("method", new Integer(TAG_METHOD));
1645: _tagMap.put("header", new Integer(TAG_HEADER));
1646: }
1647:
1648: static {
1649: base64Decode = new int[256];
1650: for (int i = 'A'; i <= 'Z'; i++)
1651: base64Decode[i] = i - 'A';
1652: for (int i = 'a'; i <= 'z'; i++)
1653: base64Decode[i] = i - 'a' + 26;
1654: for (int i = '0'; i <= '9'; i++)
1655: base64Decode[i] = i - '0' + 52;
1656: base64Decode['+'] = 62;
1657: base64Decode['/'] = 63;
1658: }
1659:
1660: static {
1661: try {
1662: _detailMessageField = Throwable.class
1663: .getDeclaredField("detailMessage");
1664: _detailMessageField.setAccessible(true);
1665: } catch (Throwable e) {
1666: }
1667: }
1668: }
|