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

package com.caucho.hessian.micro;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

Input stream for Hessian requests, compatible with microedition Java. It only uses classes and types available to J2ME. In particular, it does not have any support for the <double> type.

MicroHessianInput does not depend on any classes other than in J2ME, so it can be extracted independently into a smaller package.

MicroHessianInput is unbuffered, so any client needs to provide its own buffering.

InputStream is = ...; // from http connection
MicroHessianInput in = new MicroHessianInput(is);
String value;
in.startReply();         // read reply header
value = in.readString(); // read string value
in.completeReply();      // read reply footer
/** * Input stream for Hessian requests, compatible with microedition * Java. It only uses classes and types available to J2ME. In * particular, it does not have any support for the &lt;double> type. * * <p>MicroHessianInput does not depend on any classes other than * in J2ME, so it can be extracted independently into a smaller package. * * <p>MicroHessianInput is unbuffered, so any client needs to provide * its own buffering. * * <pre> * InputStream is = ...; // from http connection * MicroHessianInput in = new MicroHessianInput(is); * String value; * * in.startReply(); // read reply header * value = in.readString(); // read string value * in.completeReply(); // read reply footer * </pre> */
public class MicroHessianInput { protected InputStream is;
Creates a new Hessian input stream, initialized with an underlying input stream.
Params:
  • is – the underlying input stream.
/** * Creates a new Hessian input stream, initialized with an * underlying input stream. * * @param is the underlying input stream. */
public MicroHessianInput(InputStream is) { init(is); }
Creates an uninitialized Hessian input stream.
/** * Creates an uninitialized Hessian input stream. */
public MicroHessianInput() { }
Initialize the hessian stream with the underlying input stream.
/** * Initialize the hessian stream with the underlying input stream. */
public void init(InputStream is) { this.is = is; }
Starts reading the reply

A successful completion will have a single value:

r x01 x00
/** * Starts reading the reply * * <p>A successful completion will have a single value: * * <pre> * r x01 x00 * </pre> */
public void startReply() throws IOException { int tag = is.read(); if (tag != 'r') protocolException("expected hessian reply"); int major = is.read(); int minor = is.read(); }
Completes reading the call

A successful completion will have a single value:

z
/** * Completes reading the call * * <p>A successful completion will have a single value: * * <pre> * z * </pre> */
public void completeReply() throws IOException { int tag = is.read(); if (tag != 'z') protocolException("expected end of reply"); }
Reads a boolean
T
F
/** * Reads a boolean * * <pre> * T * F * </pre> */
public boolean readBoolean() throws IOException { int tag = is.read(); switch (tag) { case 'T': return true; case 'F': return false; default: throw expect("boolean", tag); } }
Reads an integer
I b32 b24 b16 b8
/** * Reads an integer * * <pre> * I b32 b24 b16 b8 * </pre> */
public int readInt() throws IOException { int tag = is.read(); if (tag != 'I') throw expect("integer", tag); int b32 = is.read(); int b24 = is.read(); int b16 = is.read(); int b8 = is.read(); return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8; }
Reads a long
L b64 b56 b48 b40 b32 b24 b16 b8
/** * Reads a long * * <pre> * L b64 b56 b48 b40 b32 b24 b16 b8 * </pre> */
public long readLong() throws IOException { int tag = is.read(); if (tag != 'L') throw protocolException("expected long"); long b64 = is.read(); long b56 = is.read(); long b48 = is.read(); long b40 = is.read(); long b32 = is.read(); long b24 = is.read(); long b16 = is.read(); long b8 = is.read(); return ((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32) + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8); }
Reads a date.
T b64 b56 b48 b40 b32 b24 b16 b8
/** * Reads a date. * * <pre> * T b64 b56 b48 b40 b32 b24 b16 b8 * </pre> */
public long readUTCDate() throws IOException { int tag = is.read(); if (tag != 'd') throw protocolException("expected date"); long b64 = is.read(); long b56 = is.read(); long b48 = is.read(); long b40 = is.read(); long b32 = is.read(); long b24 = is.read(); long b16 = is.read(); long b8 = is.read(); return ((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32) + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8); }
Reads a string
S b16 b8 string value
/** * Reads a string * * <pre> * S b16 b8 string value * </pre> */
public String readString() throws IOException { int tag = is.read(); if (tag == 'N') return null; if (tag != 'S') throw expect("string", tag); int b16 = is.read(); int b8 = is.read(); int len = (b16 << 8) + b8; return readStringImpl(len); }
Reads a byte array
B b16 b8 data value
/** * Reads a byte array * * <pre> * B b16 b8 data value * </pre> */
public byte []readBytes() throws IOException { int tag = is.read(); if (tag == 'N') return null; if (tag != 'B') throw expect("bytes", tag); int b16 = is.read(); int b8 = is.read(); int len = (b16 << 8) + b8; ByteArrayOutputStream bos = new ByteArrayOutputStream(); for (int i = 0; i < len; i++) bos.write(is.read()); return bos.toByteArray(); }
Reads an arbitrary object the input stream.
/** * Reads an arbitrary object the input stream. */
public Object readObject(Class expectedClass) throws IOException { int tag = is.read(); switch (tag) { case 'N': return null; case 'T': return new Boolean(true); case 'F': return new Boolean(false); case 'I': { int b32 = is.read(); int b24 = is.read(); int b16 = is.read(); int b8 = is.read(); return new Integer((b32 << 24) + (b24 << 16) + (b16 << 8) + b8); } case 'L': { long b64 = is.read(); long b56 = is.read(); long b48 = is.read(); long b40 = is.read(); long b32 = is.read(); long b24 = is.read(); long b16 = is.read(); long b8 = is.read(); return new Long((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32) + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8); } case 'd': { long b64 = is.read(); long b56 = is.read(); long b48 = is.read(); long b40 = is.read(); long b32 = is.read(); long b24 = is.read(); long b16 = is.read(); long b8 = is.read(); return new Date((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32) + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8); } case 'S': case 'X': { int b16 = is.read(); int b8 = is.read(); int len = (b16 << 8) + b8; return readStringImpl(len); } case 'B': { if (tag != 'B') throw expect("bytes", tag); int b16 = is.read(); int b8 = is.read(); int len = (b16 << 8) + b8; ByteArrayOutputStream bos = new ByteArrayOutputStream(); for (int i = 0; i < len; i++) bos.write(is.read()); return bos.toByteArray(); } default: throw new IOException("unknown code:" + (char) tag); } }
Reads a string from the underlying stream.
/** * Reads a string from the underlying stream. */
protected String readStringImpl(int length) throws IOException { StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int ch = is.read(); if (ch < 0x80) sb.append((char) ch); else if ((ch & 0xe0) == 0xc0) { int ch1 = is.read(); int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f); sb.append((char) v); } else if ((ch & 0xf0) == 0xe0) { int ch1 = is.read(); int ch2 = is.read(); int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f); sb.append((char) v); } else throw new IOException("bad utf-8 encoding"); } return sb.toString(); } protected IOException expect(String expect, int ch) { if (ch < 0) return protocolException("expected " + expect + " at end of file"); else return protocolException("expected " + expect + " at " + (char) ch); } protected IOException protocolException(String message) { return new IOException(message); } }