diff --git a/dubbo-remoting/dubbo-remoting-nio/pom.xml b/dubbo-remoting/dubbo-remoting-nio/pom.xml
deleted file mode 100644
index 2962b3dcaa..0000000000
--- a/dubbo-remoting/dubbo-remoting-nio/pom.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
+ * AbstractHessianInput in = ...; // get input + * String value; + * + * in.startReply(); // read reply header + * value = in.readString(); // read string value + * in.completeReply(); // read reply footer + *+ */ +abstract public class AbstractHessianInput { + private HessianRemoteResolver resolver; + + /** + * Initialize the Hessian stream with the underlying input stream. + */ + public void init(InputStream is) + { + } + + /** + * Returns the call's method + */ + abstract public String getMethod(); + + /** + * Sets the resolver used to lookup remote objects. + */ + public void setRemoteResolver(HessianRemoteResolver resolver) + { + this.resolver = resolver; + } + + /** + * Sets the resolver used to lookup remote objects. + */ + public HessianRemoteResolver getRemoteResolver() + { + return resolver; + } + + /** + * Sets the serializer factory. + */ + public void setSerializerFactory(SerializerFactory ser) + { + } + + /** + * Reads the call + * + *
+ * c major minor + *+ */ + abstract public int readCall() + throws IOException; + + /** + * For backward compatibility with HessianSkeleton + */ + public void skipOptionalCall() + throws IOException + { + } + + /** + * Reads a header, returning null if there are no headers. + * + *
+ * H b16 b8 value + *+ */ + abstract public String readHeader() + throws IOException; + + /** + * Starts reading the call + * + *
A successful completion will have a single value: + * + *
+ * m b16 b8 method + *+ */ + abstract public String readMethod() + throws IOException; + + /** + * Reads the number of method arguments + * + * @return -1 for a variable length (hessian 1.0) + */ + public int readMethodArgLength() + throws IOException + { + return -1; + } + + /** + * Starts reading the call, including the headers. + * + *
The call expects the following protocol data + * + *
+ * c major minor + * m b16 b8 method + *+ */ + abstract public void startCall() + throws IOException; + + /** + * Completes reading the call + * + *
The call expects the following protocol data + * + *
+ * Z + *+ */ + abstract public void completeCall() + throws IOException; + + /** + * Reads a reply as an object. + * If the reply has a fault, throws the exception. + */ + abstract public Object readReply(Class expectedClass) + throws Throwable; + + /** + * Starts reading the reply + * + *
A successful completion will have a single value: + * + *
+ * r + * v + *+ */ + abstract public void startReply() + throws Throwable; + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + abstract public void completeReply() + throws IOException; + + /** + * Reads a boolean + * + *
+ * T + * F + *+ */ + abstract public boolean readBoolean() + throws IOException; + + /** + * Reads a null + * + *
+ * N + *+ */ + abstract public void readNull() + throws IOException; + + /** + * Reads an integer + * + *
+ * I b32 b24 b16 b8 + *+ */ + abstract public int readInt() + throws IOException; + + /** + * Reads a long + * + *
+ * L b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + abstract public long readLong() + throws IOException; + + /** + * Reads a double. + * + *
+ * D b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + abstract public double readDouble() + throws IOException; + + /** + * Reads a date. + * + *
+ * T b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + abstract public long readUTCDate() + throws IOException; + + /** + * Reads a string encoded in UTF-8 + * + *
+ * s b16 b8 non-final string chunk + * S b16 b8 final string chunk + *+ */ + abstract public String readString() + throws IOException; + + /** + * Reads an XML node encoded in UTF-8 + * + *
+ * x b16 b8 non-final xml chunk + * X b16 b8 final xml chunk + *+ */ + public org.w3c.dom.Node readNode() + throws IOException + { + throw new UnsupportedOperationException(getClass().getSimpleName()); + } + + /** + * Starts reading a string. All the characters must be read before + * calling the next method. The actual characters will be read with + * the reader's read() or read(char [], int, int). + * + *
+ * s b16 b8 non-final string chunk + * S b16 b8 final string chunk + *+ */ + abstract public Reader getReader() + throws IOException; + + /** + * Starts reading a byte array using an input stream. All the bytes + * must be read before calling the following method. + * + *
+ * b b16 b8 non-final binary chunk + * B b16 b8 final binary chunk + *+ */ + abstract public InputStream readInputStream() + throws IOException; + + /** + * Reads a byte array. + * + *
+ * b b16 b8 non-final binary chunk + * B b16 b8 final binary chunk + *+ */ + abstract public byte []readBytes() + throws IOException; + + /** + * Reads an arbitrary object from the input stream. + * + * @param expectedClass the expected class if the protocol doesn't supply it. + */ + abstract public Object readObject(Class expectedClass) + throws IOException; + + /** + * Reads an arbitrary object from the input stream. + */ + abstract public Object readObject() + throws IOException; + + /** + * Reads a remote object reference to the stream. The type is the + * type of the remote interface. + * + *
+ * 'r' 't' b16 b8 type url
+ *
+ */
+ abstract public Object readRemote()
+ throws IOException;
+
+ /**
+ * Reads a reference
+ *
+ * + * R b32 b24 b16 b8 + *+ */ + abstract public Object readRef() + throws IOException; + + /** + * Adds an object reference. + */ + abstract public int addRef(Object obj) + throws IOException; + + /** + * Sets an object reference. + */ + abstract public void setRef(int i, Object obj) + throws IOException; + + /** + * Resets the references for streaming. + */ + public void resetReferences() + { + } + + /** + * Reads the start of a list + */ + abstract public int readListStart() + throws IOException; + + /** + * Reads the length of a list. + */ + abstract public int readLength() + throws IOException; + + /** + * Reads the start of a map + */ + abstract public int readMapStart() + throws IOException; + + /** + * Reads an object type. + */ + abstract public String readType() + throws IOException; + + /** + * Returns true if the data has ended. + */ + abstract public boolean isEnd() + throws IOException; + + /** + * Read the end byte + */ + abstract public void readEnd() + throws IOException; + + /** + * Read the end byte + */ + abstract public void readMapEnd() + throws IOException; + + /** + * Read the end byte + */ + abstract public void readListEnd() + throws IOException; + + public void close() + throws IOException + { + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java new file mode 100644 index 0000000000..f61732f54d --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java @@ -0,0 +1,531 @@ +/* + * 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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Abstract output stream for Hessian requests. + * + *
+ * OutputStream os = ...; // from http connection
+ * AbstractOutput out = new HessianSerializerOutput(os);
+ * String value;
+ *
+ * out.startCall("hello"); // start hello call
+ * out.writeString("arg1"); // write a string argument
+ * out.completeCall(); // complete the call
+ *
+ */
+abstract public class AbstractHessianOutput {
+ // serializer factory
+ protected SerializerFactory _serializerFactory;
+
+ /**
+ * Sets the serializer factory.
+ */
+ public void setSerializerFactory(SerializerFactory factory)
+ {
+ _serializerFactory = factory;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ public SerializerFactory getSerializerFactory()
+ {
+ return _serializerFactory;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ public final SerializerFactory findSerializerFactory()
+ {
+ SerializerFactory factory = _serializerFactory;
+
+ if (factory == null)
+ _serializerFactory = factory = new SerializerFactory();
+
+ return factory;
+ }
+
+ /**
+ * Initialize the output with a new underlying stream.
+ */
+ public void init(OutputStream os)
+ {
+ }
+
+ /**
+ * Writes a complete method call.
+ */
+ public void call(String method, Object []args)
+ throws IOException
+ {
+ int length = args != null ? args.length : 0;
+
+ startCall(method, length);
+
+ for (int i = 0; i < length; i++)
+ writeObject(args[i]);
+
+ completeCall();
+ }
+
+ /**
+ * Starts the method call:
+ *
+ *
+ * C
+ *
+ *
+ * @param method the method name to call.
+ */
+ abstract public void startCall()
+ throws IOException;
+
+ /**
+ * Starts the method call:
+ *
+ *
+ * C string int
+ *
+ *
+ * @param method the method name to call.
+ */
+ abstract public void startCall(String method, int length)
+ throws IOException;
+
+ /**
+ * For Hessian 2.0, use the Header envelope instead
+ *
+ * @deprecated
+ */
+ public void writeHeader(String name)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(getClass().getSimpleName());
+ }
+
+ /**
+ * Writes the method tag.
+ *
+ *
+ * string
+ *
+ *
+ * @param method the method name to call.
+ */
+ abstract public void writeMethod(String method)
+ throws IOException;
+
+ /**
+ * Completes the method call:
+ *
+ *
+ *
+ */
+ abstract public void completeCall()
+ throws IOException;
+
+ /**
+ * Writes a boolean value to the stream. The boolean will be written
+ * with the following syntax:
+ *
+ *
+ * T
+ * F
+ *
+ *
+ * @param value the boolean value to write.
+ */
+ abstract public void writeBoolean(boolean value)
+ throws IOException;
+
+ /**
+ * Writes an integer value to the stream. The integer will be written
+ * with the following syntax:
+ *
+ *
+ * I b32 b24 b16 b8
+ *
+ *
+ * @param value the integer value to write.
+ */
+ abstract public void writeInt(int value)
+ throws IOException;
+
+ /**
+ * Writes a long value to the stream. The long will be written
+ * with the following syntax:
+ *
+ *
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param value the long value to write.
+ */
+ abstract public void writeLong(long value)
+ throws IOException;
+
+ /**
+ * Writes a double value to the stream. The double will be written
+ * with the following syntax:
+ *
+ *
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param value the double value to write.
+ */
+ abstract public void writeDouble(double value)
+ throws IOException;
+
+ /**
+ * Writes a date to the stream.
+ *
+ *
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param time the date in milliseconds from the epoch in UTC
+ */
+ abstract public void writeUTCDate(long time)
+ throws IOException;
+
+ /**
+ * Writes a null value to the stream.
+ * The null will be written with the following syntax
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeNull()
+ throws IOException;
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeString(String value)
+ throws IOException;
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeString(char []buffer, int offset, int length)
+ throws IOException;
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeBytes(byte []buffer)
+ throws IOException;
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeBytes(byte []buffer, int offset, int length)
+ throws IOException;
+
+ /**
+ * Writes a byte buffer to the stream.
+ */
+ abstract public void writeByteBufferStart()
+ throws IOException;
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeByteBufferPart(byte []buffer,
+ int offset,
+ int length)
+ throws IOException;
+
+ /**
+ * Writes the last chunk of a byte buffer to the stream.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeByteBufferEnd(byte []buffer,
+ int offset,
+ int length)
+ throws IOException;
+
+ /**
+ * Writes a reference.
+ *
+ *
+ * Q int
+ *
+ *
+ * @param value the integer value to write.
+ */
+ abstract protected void writeRef(int value)
+ throws IOException;
+
+ /**
+ * Removes a reference.
+ */
+ abstract public boolean removeRef(Object obj)
+ throws IOException;
+
+ /**
+ * Replaces a reference from one object to another.
+ */
+ abstract public boolean replaceRef(Object oldRef, Object newRef)
+ throws IOException;
+
+ /**
+ * Adds an object to the reference list. If the object already exists,
+ * writes the reference, otherwise, the caller is responsible for
+ * the serialization.
+ *
+ *
+ * R b32 b24 b16 b8
+ *
+ *
+ * @param object the object to add as a reference.
+ *
+ * @return true if the object has already been written.
+ */
+ abstract public boolean addRef(Object object)
+ throws IOException;
+
+ /**
+ * Resets the references for streaming.
+ */
+ public void resetReferences()
+ {
+ }
+
+ /**
+ * Writes a generic object to the output stream.
+ */
+ abstract public void writeObject(Object object)
+ throws IOException;
+
+ /**
+ * Writes the list header to the stream. List writers will call
+ * writeListBegin followed by the list contents and then
+ * call writeListEnd.
+ *
+ *
+ * V
+ * x13 java.util.ArrayList # type
+ * x93 # length=3
+ * x91 # 1
+ * x92 # 2
+ * x93 # 3
+ * </list>
+ *
+ */
+ abstract public boolean writeListBegin(int length, String type)
+ throws IOException;
+
+ /**
+ * Writes the tail of the list to the stream.
+ */
+ abstract public void writeListEnd()
+ throws IOException;
+
+ /**
+ * Writes the map header to the stream. Map writers will call
+ * writeMapBegin followed by the map contents and then
+ * call writeMapEnd.
+ *
+ *
+ * M type ( )* Z
+ *
+ */
+ abstract public void writeMapBegin(String type)
+ throws IOException;
+
+ /**
+ * Writes the tail of the map to the stream.
+ */
+ abstract public void writeMapEnd()
+ throws IOException;
+
+ /**
+ * Writes the object header to the stream (for Hessian 2.0), or a
+ * Map for Hessian 1.0. Object writers will call
+ * writeObjectBegin followed by the map contents and then
+ * call writeObjectEnd.
+ *
+ *
+ * C type int *
+ * C int *
+ *
+ *
+ * @return true if the object has already been defined.
+ */
+ public int writeObjectBegin(String type)
+ throws IOException
+ {
+ writeMapBegin(type);
+
+ return -2;
+ }
+
+ /**
+ * Writes the end of the class.
+ */
+ public void writeClassFieldLength(int len)
+ throws IOException
+ {
+ }
+
+ /**
+ * Writes the tail of the object to the stream.
+ */
+ public void writeObjectEnd()
+ throws IOException
+ {
+ }
+
+ public void writeReply(Object o)
+ throws IOException
+ {
+ startReply();
+ writeObject(o);
+ completeReply();
+ }
+
+
+ public void startReply()
+ throws IOException
+ {
+ }
+
+ public void completeReply()
+ throws IOException
+ {
+ }
+
+ public void writeFault(String code, String message, Object detail)
+ throws IOException
+ {
+ }
+
+ public void flush()
+ throws IOException
+ {
+ }
+
+ public void close()
+ throws IOException
+ {
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
new file mode 100644
index 0000000000..ae42285c98
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Looks up remote objects. The default just returns a HessianRemote object.
+ */
+public class AbstractHessianResolver implements HessianRemoteResolver {
+ /**
+ * Looks up a proxy object.
+ */
+ public Object lookup(String type, String url)
+ throws IOException
+ {
+ return new HessianRemote(type, url);
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java
new file mode 100644
index 0000000000..20318b9d65
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializing a JDK 1.2 Collection.
+ */
+public class AbstractListDeserializer extends AbstractDeserializer {
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ Object obj = in.readObject();
+
+ if (obj != null)
+ throw error("expected list at " + obj.getClass().getName() + " (" + obj + ")");
+ else
+ throw error("expected list at null");
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java
new file mode 100644
index 0000000000..7a90a7912a
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class AbstractMapDeserializer extends AbstractDeserializer {
+
+ public Class getType()
+ {
+ return HashMap.class;
+ }
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ Object obj = in.readObject();
+
+ if (obj != null)
+ throw error("expected map/object at " + obj.getClass().getName() + " (" + obj + ")");
+ else
+ throw error("expected map/object at null");
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java
new file mode 100644
index 0000000000..df450cf340
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.logging.*;
+
+/**
+ * Serializing an object.
+ */
+abstract public class AbstractSerializer implements Serializer {
+ protected static final Logger log
+ = Logger.getLogger(AbstractSerializer.class.getName());
+
+ abstract public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException;
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializerFactory.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializerFactory.java
new file mode 100644
index 0000000000..cc66de7ce8
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializerFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+/**
+ * Factory for returning serialization methods.
+ */
+abstract public class AbstractSerializerFactory {
+ /**
+ * Returns the serializer for a class.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ *
+ * @return a serializer object for the serialization.
+ */
+ abstract public Serializer getSerializer(Class cl)
+ throws HessianProtocolException;
+
+ /**
+ * Returns the deserializer for a class.
+ *
+ * @param cl the class of the object that needs to be deserialized.
+ *
+ * @return a deserializer object for the serialization.
+ */
+ abstract public Deserializer getDeserializer(Class cl)
+ throws HessianProtocolException;
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java
new file mode 100644
index 0000000000..cf8fc6e7e2
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+
+/**
+ * Deserializing a Java array
+ */
+public class ArrayDeserializer extends AbstractListDeserializer {
+ private Class _componentType;
+ private Class _type;
+
+ public ArrayDeserializer(Class componentType)
+ {
+ _componentType = componentType;
+
+ if (_componentType != null) {
+ try {
+ _type = Array.newInstance(_componentType, 0).getClass();
+ } catch (Exception e) {
+ }
+ }
+
+ if (_type == null)
+ _type = Object[].class;
+ }
+
+ public Class getType()
+ {
+ return _type;
+ }
+
+ /**
+ * Reads the array.
+ */
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException
+ {
+ if (length >= 0) {
+ Object []data = createArray(length);
+
+ in.addRef(data);
+
+ if (_componentType != null) {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject(_componentType);
+ }
+ else {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+ }
+
+ in.readListEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ in.addRef(list);
+
+ if (_componentType != null) {
+ while (! in.isEnd())
+ list.add(in.readObject(_componentType));
+ }
+ else {
+ while (! in.isEnd())
+ list.add(in.readObject());
+ }
+
+ in.readListEnd();
+
+ Object []data = createArray(list.size());
+ for (int i = 0; i < data.length; i++)
+ data[i] = list.get(i);
+
+ return data;
+ }
+ }
+
+ /**
+ * Reads the array.
+ */
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException
+ {
+ Object []data = createArray(length);
+
+ in.addRef(data);
+
+ if (_componentType != null) {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject(_componentType);
+ }
+ else {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+ }
+
+ return data;
+ }
+
+ protected Object []createArray(int length)
+ {
+ if (_componentType != null)
+ return (Object []) Array.newInstance(_componentType, length);
+ else
+ return new Object[length];
+ }
+
+ public String toString()
+ {
+ return "ArrayDeserializer[" + _componentType + "]";
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java
new file mode 100644
index 0000000000..7bcfe90f84
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Serializing a Java array.
+ */
+public class ArraySerializer extends AbstractSerializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (out.addRef(obj))
+ return;
+
+ Object []array = (Object []) obj;
+
+ boolean hasEnd = out.writeListBegin(array.length,
+ getArrayType(obj.getClass()));
+
+ for (int i = 0; i < array.length; i++)
+ out.writeObject(array[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ }
+
+ /**
+ * Returns the <type> name for a <list>.
+ */
+ private String getArrayType(Class cl)
+ {
+ if (cl.isArray())
+ return '[' + getArrayType(cl.getComponentType());
+
+ String name = cl.getName();
+
+ if (name.equals("java.lang.String"))
+ return "string";
+ else if (name.equals("java.lang.Object"))
+ return "object";
+ else if (name.equals("java.util.Date"))
+ return "date";
+ else
+ return name;
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
new file mode 100644
index 0000000000..a0e860f698
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
@@ -0,0 +1,608 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BasicDeserializer extends AbstractDeserializer {
+ public static final int NULL = BasicSerializer.NULL;
+ public static final int BOOLEAN = BasicSerializer.BOOLEAN;
+ public static final int BYTE = BasicSerializer.BYTE;
+ public static final int SHORT = BasicSerializer.SHORT;
+ public static final int INTEGER = BasicSerializer.INTEGER;
+ public static final int LONG = BasicSerializer.LONG;
+ public static final int FLOAT = BasicSerializer.FLOAT;
+ public static final int DOUBLE = BasicSerializer.DOUBLE;
+ public static final int CHARACTER = BasicSerializer.CHARACTER;
+ public static final int CHARACTER_OBJECT = BasicSerializer.CHARACTER_OBJECT;
+ public static final int STRING = BasicSerializer.STRING;
+ public static final int DATE = BasicSerializer.DATE;
+ public static final int NUMBER = BasicSerializer.NUMBER;
+ public static final int OBJECT = BasicSerializer.OBJECT;
+
+ public static final int BOOLEAN_ARRAY = BasicSerializer.BOOLEAN_ARRAY;
+ public static final int BYTE_ARRAY = BasicSerializer.BYTE_ARRAY;
+ public static final int SHORT_ARRAY = BasicSerializer.SHORT_ARRAY;
+ public static final int INTEGER_ARRAY = BasicSerializer.INTEGER_ARRAY;
+ public static final int LONG_ARRAY = BasicSerializer.LONG_ARRAY;
+ public static final int FLOAT_ARRAY = BasicSerializer.FLOAT_ARRAY;
+ public static final int DOUBLE_ARRAY = BasicSerializer.DOUBLE_ARRAY;
+ public static final int CHARACTER_ARRAY = BasicSerializer.CHARACTER_ARRAY;
+ public static final int STRING_ARRAY = BasicSerializer.STRING_ARRAY;
+ public static final int OBJECT_ARRAY = BasicSerializer.OBJECT_ARRAY;
+
+ private int _code;
+
+ public BasicDeserializer(int code)
+ {
+ _code = code;
+ }
+
+ public Class getType()
+ {
+ switch (_code) {
+ case NULL:
+ return void.class;
+ case BOOLEAN:
+ return Boolean.class;
+ case BYTE:
+ return Byte.class;
+ case SHORT:
+ return Short.class;
+ case INTEGER:
+ return Integer.class;
+ case LONG:
+ return Long.class;
+ case FLOAT:
+ return Float.class;
+ case DOUBLE:
+ return Double.class;
+ case CHARACTER:
+ return Character.class;
+ case CHARACTER_OBJECT:
+ return Character.class;
+ case STRING:
+ return String.class;
+ case DATE:
+ return Date.class;
+ case NUMBER:
+ return Number.class;
+ case OBJECT:
+ return Object.class;
+
+ case BOOLEAN_ARRAY:
+ return boolean[].class;
+ case BYTE_ARRAY:
+ return byte[].class;
+ case SHORT_ARRAY:
+ return short[].class;
+ case INTEGER_ARRAY:
+ return int[].class;
+ case LONG_ARRAY:
+ return long[].class;
+ case FLOAT_ARRAY:
+ return float[].class;
+ case DOUBLE_ARRAY:
+ return double[].class;
+ case CHARACTER_ARRAY:
+ return char[].class;
+ case STRING_ARRAY:
+ return String[].class;
+ case OBJECT_ARRAY:
+ return Object[].class;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ switch (_code) {
+ case NULL:
+ // hessian/3490
+ in.readObject();
+
+ return null;
+
+ case BOOLEAN:
+ return Boolean.valueOf(in.readBoolean());
+
+ case BYTE:
+ return Byte.valueOf((byte) in.readInt());
+
+ case SHORT:
+ return Short.valueOf((short) in.readInt());
+
+ case INTEGER:
+ return Integer.valueOf(in.readInt());
+
+ case LONG:
+ return Long.valueOf(in.readLong());
+
+ case FLOAT:
+ return Float.valueOf((float) in.readDouble());
+
+ case DOUBLE:
+ return Double.valueOf(in.readDouble());
+
+ case STRING:
+ return in.readString();
+
+ case OBJECT:
+ return in.readObject();
+
+ case CHARACTER:
+ {
+ String s = in.readString();
+ if (s == null || s.equals(""))
+ return Character.valueOf((char) 0);
+ else
+ return Character.valueOf(s.charAt(0));
+ }
+
+ case CHARACTER_OBJECT:
+ {
+ String s = in.readString();
+ if (s == null || s.equals(""))
+ return null;
+ else
+ return Character.valueOf(s.charAt(0));
+ }
+
+ case DATE:
+ return new Date(in.readUTCDate());
+
+ case NUMBER:
+ return in.readObject();
+
+ case BYTE_ARRAY:
+ return in.readBytes();
+
+ case CHARACTER_ARRAY:
+ {
+ String s = in.readString();
+
+ if (s == null)
+ return null;
+ else {
+ int len = s.length();
+ char []chars = new char[len];
+ s.getChars(0, len, chars, 0);
+ return chars;
+ }
+ }
+
+ case BOOLEAN_ARRAY:
+ case SHORT_ARRAY:
+ case INTEGER_ARRAY:
+ case LONG_ARRAY:
+ case FLOAT_ARRAY:
+ case DOUBLE_ARRAY:
+ case STRING_ARRAY:
+ {
+ int code = in.readListStart();
+
+ switch (code) {
+ case 'N':
+ return null;
+
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ int length = code - 0x10;
+ in.readInt();
+
+ return readLengthList(in, length);
+
+ default:
+ String type = in.readType();
+ length = in.readLength();
+
+ return readList(in, length);
+ }
+ }
+
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException
+ {
+ switch (_code) {
+ case BOOLEAN_ARRAY: {
+ if (length >= 0) {
+ boolean []data = new boolean[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readBoolean();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(Boolean.valueOf(in.readBoolean()));
+
+ in.readEnd();
+
+ boolean []data = new boolean[list.size()];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Boolean) list.get(i)).booleanValue();
+
+ return data;
+ }
+ }
+
+ case SHORT_ARRAY: {
+ if (length >= 0) {
+ short []data = new short[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (short) in.readInt();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(Short.valueOf((short) in.readInt()));
+
+ in.readEnd();
+
+ short []data = new short[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Short) list.get(i)).shortValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case INTEGER_ARRAY: {
+ if (length >= 0) {
+ int []data = new int[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readInt();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(Integer.valueOf(in.readInt()));
+
+
+ in.readEnd();
+
+ int []data = new int[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Integer) list.get(i)).intValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case LONG_ARRAY: {
+ if (length >= 0) {
+ long []data = new long[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readLong();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(Long.valueOf(in.readLong()));
+
+ in.readEnd();
+
+ long []data = new long[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Long) list.get(i)).longValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case FLOAT_ARRAY: {
+ if (length >= 0) {
+ float []data = new float[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (float) in.readDouble();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(new Float(in.readDouble()));
+
+ in.readEnd();
+
+ float []data = new float[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Float) list.get(i)).floatValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case DOUBLE_ARRAY: {
+ if (length >= 0) {
+ double []data = new double[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readDouble();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(new Double(in.readDouble()));
+
+ in.readEnd();
+
+ double []data = new double[list.size()];
+ in.addRef(data);
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Double) list.get(i)).doubleValue();
+
+ return data;
+ }
+ }
+
+ case STRING_ARRAY: {
+ if (length >= 0) {
+ String []data = new String[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readString();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ while (! in.isEnd())
+ list.add(in.readString());
+
+ in.readEnd();
+
+ String []data = new String[list.size()];
+ in.addRef(data);
+ for (int i = 0; i < data.length; i++)
+ data[i] = (String) list.get(i);
+
+ return data;
+ }
+ }
+
+ case OBJECT_ARRAY: {
+ if (length >= 0) {
+ Object []data = new Object[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+
+ in.readEnd();
+
+ return data;
+ }
+ else {
+ ArrayList list = new ArrayList();
+
+ in.addRef(list); // XXX: potential issues here
+
+ while (! in.isEnd())
+ list.add(in.readObject());
+
+ in.readEnd();
+
+ Object []data = new Object[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = (Object) list.get(i);
+
+ return data;
+ }
+ }
+
+ default:
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+ }
+
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException
+ {
+ switch (_code) {
+ case BOOLEAN_ARRAY: {
+ boolean []data = new boolean[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readBoolean();
+
+ return data;
+ }
+
+ case SHORT_ARRAY: {
+ short []data = new short[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (short) in.readInt();
+
+ return data;
+ }
+
+ case INTEGER_ARRAY: {
+ int []data = new int[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readInt();
+
+ return data;
+ }
+
+ case LONG_ARRAY: {
+ long []data = new long[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readLong();
+
+ return data;
+ }
+
+ case FLOAT_ARRAY: {
+ float []data = new float[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (float) in.readDouble();
+
+ return data;
+ }
+
+ case DOUBLE_ARRAY: {
+ double []data = new double[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readDouble();
+
+ return data;
+ }
+
+ case STRING_ARRAY: {
+ String []data = new String[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readString();
+
+ return data;
+ }
+
+ case OBJECT_ARRAY: {
+ Object []data = new Object[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+
+ return data;
+ }
+
+ default:
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java
new file mode 100644
index 0000000000..2feb40b655
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BasicSerializer extends AbstractSerializer {
+ public static final int NULL = 0;
+ public static final int BOOLEAN = NULL + 1;
+ public static final int BYTE = BOOLEAN + 1;
+ public static final int SHORT = BYTE + 1;
+ public static final int INTEGER = SHORT + 1;
+ public static final int LONG = INTEGER + 1;
+ public static final int FLOAT = LONG + 1;
+ public static final int DOUBLE = FLOAT + 1;
+ public static final int CHARACTER = DOUBLE + 1;
+ public static final int CHARACTER_OBJECT = CHARACTER + 1;
+ public static final int STRING = CHARACTER_OBJECT + 1;
+ public static final int DATE = STRING + 1;
+ public static final int NUMBER = DATE + 1;
+ public static final int OBJECT = NUMBER + 1;
+
+ public static final int BOOLEAN_ARRAY = OBJECT + 1;
+ public static final int BYTE_ARRAY = BOOLEAN_ARRAY + 1;
+ public static final int SHORT_ARRAY = BYTE_ARRAY + 1;
+ public static final int INTEGER_ARRAY = SHORT_ARRAY + 1;
+ public static final int LONG_ARRAY = INTEGER_ARRAY + 1;
+ public static final int FLOAT_ARRAY = LONG_ARRAY + 1;
+ public static final int DOUBLE_ARRAY = FLOAT_ARRAY + 1;
+ public static final int CHARACTER_ARRAY = DOUBLE_ARRAY + 1;
+ public static final int STRING_ARRAY = CHARACTER_ARRAY + 1;
+ public static final int OBJECT_ARRAY = STRING_ARRAY + 1;
+
+ private int code;
+
+ public BasicSerializer(int code)
+ {
+ this.code = code;
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ switch (code) {
+ case BOOLEAN:
+ out.writeBoolean(((Boolean) obj).booleanValue());
+ break;
+
+ case BYTE:
+ case SHORT:
+ case INTEGER:
+ out.writeInt(((Number) obj).intValue());
+ break;
+
+ case LONG:
+ out.writeLong(((Number) obj).longValue());
+ break;
+
+ case FLOAT:
+ case DOUBLE:
+ out.writeDouble(((Number) obj).doubleValue());
+ break;
+
+ case CHARACTER:
+ case CHARACTER_OBJECT:
+ out.writeString(String.valueOf(obj));
+ break;
+
+ case STRING:
+ out.writeString((String) obj);
+ break;
+
+ case DATE:
+ out.writeUTCDate(((Date) obj).getTime());
+ break;
+
+ case BOOLEAN_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ boolean []data = (boolean []) obj;
+ boolean hasEnd = out.writeListBegin(data.length, "[boolean");
+ for (int i = 0; i < data.length; i++)
+ out.writeBoolean(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+
+ break;
+ }
+
+ case BYTE_ARRAY:
+ {
+ byte []data = (byte []) obj;
+ out.writeBytes(data, 0, data.length);
+ break;
+ }
+
+ case SHORT_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ short []data = (short []) obj;
+ boolean hasEnd = out.writeListBegin(data.length, "[short");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeInt(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case INTEGER_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ int []data = (int []) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[int");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeInt(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+
+ break;
+ }
+
+ case LONG_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ long []data = (long []) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[long");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeLong(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case FLOAT_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ float []data = (float []) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[float");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeDouble(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case DOUBLE_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ double []data = (double []) obj;
+ boolean hasEnd = out.writeListBegin(data.length, "[double");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeDouble(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case STRING_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ String []data = (String []) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[string");
+
+ for (int i = 0; i < data.length; i++) {
+ out.writeString(data[i]);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case CHARACTER_ARRAY:
+ {
+ char []data = (char []) obj;
+ out.writeString(data, 0, data.length);
+ break;
+ }
+
+ case OBJECT_ARRAY:
+ {
+ if (out.addRef(obj))
+ return;
+
+ Object []data = (Object []) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[object");
+
+ for (int i = 0; i < data.length; i++) {
+ out.writeObject(data[i]);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case NULL:
+ out.writeNull();
+ break;
+
+ default:
+ throw new RuntimeException(code + " " + String.valueOf(obj.getClass()));
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java
new file mode 100644
index 0000000000..f669c70c6f
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java
@@ -0,0 +1,295 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BeanDeserializer extends AbstractMapDeserializer {
+ private Class _type;
+ private HashMap _methodMap;
+ private Method _readResolve;
+ private Constructor _constructor;
+ private Object []_constructorArgs;
+
+ public BeanDeserializer(Class cl)
+ {
+ _type = cl;
+ _methodMap = getMethodMap(cl);
+
+ _readResolve = getReadResolve(cl);
+
+ Constructor []constructors = cl.getConstructors();
+ int bestLength = Integer.MAX_VALUE;
+
+ for (int i = 0; i < constructors.length; i++) {
+ if (constructors[i].getParameterTypes().length < bestLength) {
+ _constructor = constructors[i];
+ bestLength = _constructor.getParameterTypes().length;
+ }
+ }
+
+ if (_constructor != null) {
+ _constructor.setAccessible(true);
+ Class []params = _constructor.getParameterTypes();
+ _constructorArgs = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ _constructorArgs[i] = getParamArg(params[i]);
+ }
+ }
+ }
+
+ public Class getType()
+ {
+ return _type;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ try {
+ Object obj = instantiate();
+
+ return readMap(in, obj);
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ public Object readMap(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ try {
+ int ref = in.addRef(obj);
+
+ while (! in.isEnd()) {
+ Object key = in.readObject();
+
+ Method method = (Method) _methodMap.get(key);
+
+ if (method != null) {
+ Object value = in.readObject(method.getParameterTypes()[0]);
+
+ method.invoke(obj, new Object[] {value });
+ }
+ else {
+ Object value = in.readObject();
+ }
+ }
+
+ in.readMapEnd();
+
+ Object resolve = resolve(obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ private Object resolve(Object obj)
+ {
+ // if there's a readResolve method, call it
+ try {
+ if (_readResolve != null)
+ return _readResolve.invoke(obj, new Object[0]);
+ } catch (Exception e) {
+ }
+
+ return obj;
+ }
+
+ protected Object instantiate()
+ throws Exception
+ {
+ return _constructor.newInstance(_constructorArgs);
+ }
+
+ /**
+ * Returns the readResolve method
+ */
+ protected Method getReadResolve(Class cl)
+ {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method []methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("readResolve") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected HashMap getMethodMap(Class cl)
+ {
+ HashMap methodMap = new HashMap();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method []methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (Modifier.isStatic(method.getModifiers()))
+ continue;
+
+ String name = method.getName();
+
+ if (! name.startsWith("set"))
+ continue;
+
+ Class []paramTypes = method.getParameterTypes();
+ if (paramTypes.length != 1)
+ continue;
+
+ if (! method.getReturnType().equals(void.class))
+ continue;
+
+ if (findGetter(methods, name, paramTypes[0]) == null)
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ method.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ name = name.substring(3);
+
+ int j = 0;
+ for (; j < name.length() && Character.isUpperCase(name.charAt(j)); j++) {
+ }
+
+ if (j == 1)
+ name = name.substring(0, j).toLowerCase() + name.substring(j);
+ else if (j > 1)
+ name = name.substring(0, j - 1).toLowerCase() + name.substring(j - 1);
+
+
+ methodMap.put(name, method);
+ }
+ }
+
+ return methodMap;
+ }
+
+ /**
+ * Finds any matching setter.
+ */
+ private Method findGetter(Method []methods, String setterName, Class arg)
+ {
+ String getterName = "get" + setterName.substring(3);
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (! method.getName().equals(getterName))
+ continue;
+
+ if (! method.getReturnType().equals(arg))
+ continue;
+
+ Class []params = method.getParameterTypes();
+
+ if (params.length == 0)
+ return method;
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected static Object getParamArg(Class cl)
+ {
+ if (! cl.isPrimitive())
+ return null;
+ else if (boolean.class.equals(cl))
+ return Boolean.FALSE;
+ else if (byte.class.equals(cl))
+ return Byte.valueOf((byte) 0);
+ else if (short.class.equals(cl))
+ return Short.valueOf((short) 0);
+ else if (char.class.equals(cl))
+ return Character.valueOf((char) 0);
+ else if (int.class.equals(cl))
+ return Integer.valueOf(0);
+ else if (long.class.equals(cl))
+ return Long.valueOf(0);
+ else if (float.class.equals(cl))
+ return Double.valueOf(0);
+ else if (double.class.equals(cl))
+ return Double.valueOf(0);
+ else
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializer.java
new file mode 100644
index 0000000000..40dd166891
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializer.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.logging.*;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BeanSerializer extends AbstractSerializer {
+ private static final Logger log
+ = Logger.getLogger(BeanSerializer.class.getName());
+
+ private static final Object []NULL_ARGS = new Object[0];
+ private Method []_methods;
+ private String []_names;
+
+ private Object _writeReplaceFactory;
+ private Method _writeReplace;
+
+ public BeanSerializer(Class cl, ClassLoader loader)
+ {
+ introspectWriteReplace(cl, loader);
+
+ ArrayList primitiveMethods = new ArrayList();
+ ArrayList compoundMethods = new ArrayList();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method []methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (Modifier.isStatic(method.getModifiers()))
+ continue;
+
+ if (method.getParameterTypes().length != 0)
+ continue;
+
+ String name = method.getName();
+
+ if (! name.startsWith("get"))
+ continue;
+
+ Class type = method.getReturnType();
+
+ if (type.equals(void.class))
+ continue;
+
+ if (findSetter(methods, name, type) == null)
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ method.setAccessible(true);
+
+ if (type.isPrimitive()
+ || type.getName().startsWith("java.lang.")
+ && ! type.equals(Object.class))
+ primitiveMethods.add(method);
+ else
+ compoundMethods.add(method);
+ }
+ }
+
+ ArrayList methodList = new ArrayList();
+ methodList.addAll(primitiveMethods);
+ methodList.addAll(compoundMethods);
+
+ Collections.sort(methodList, new MethodNameCmp());
+
+ _methods = new Method[methodList.size()];
+ methodList.toArray(_methods);
+
+ _names = new String[_methods.length];
+
+ for (int i = 0; i < _methods.length; i++) {
+ String name = _methods[i].getName();
+
+ name = name.substring(3);
+
+ int j = 0;
+ for (; j < name.length() && Character.isUpperCase(name.charAt(j)); j++) {
+ }
+
+ if (j == 1)
+ name = name.substring(0, j).toLowerCase() + name.substring(j);
+ else if (j > 1)
+ name = name.substring(0, j - 1).toLowerCase() + name.substring(j - 1);
+
+ _names[i] = name;
+ }
+ }
+
+ private void introspectWriteReplace(Class cl, ClassLoader loader)
+ {
+ try {
+ String className = cl.getName() + "HessianSerializer";
+
+ Class serializerClass = Class.forName(className, false, loader);
+
+ Object serializerObject = serializerClass.newInstance();
+
+ Method writeReplace = getWriteReplace(serializerClass, cl);
+
+ if (writeReplace != null) {
+ _writeReplaceFactory = serializerObject;
+ _writeReplace = writeReplace;
+
+ return;
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (Exception e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ _writeReplace = getWriteReplace(cl);
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected Method getWriteReplace(Class cl)
+ {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method []methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("writeReplace") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected Method getWriteReplace(Class cl, Class param)
+ {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ for (Method method : cl.getDeclaredMethods()) {
+ if (method.getName().equals("writeReplace")
+ && method.getParameterTypes().length == 1
+ && param.equals(method.getParameterTypes()[0]))
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (out.addRef(obj))
+ return;
+
+ Class cl = obj.getClass();
+
+ try {
+ if (_writeReplace != null) {
+ Object repl;
+
+ if (_writeReplaceFactory != null)
+ repl = _writeReplace.invoke(_writeReplaceFactory, obj);
+ else
+ repl = _writeReplace.invoke(obj);
+
+ out.removeRef(obj);
+
+ out.writeObject(repl);
+
+ out.replaceRef(repl, obj);
+
+ return;
+ }
+ } catch (Exception e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ // Hessian 1.1 uses a map
+
+ for (int i = 0; i < _methods.length; i++) {
+ Method method = _methods[i];
+ Object value = null;
+
+ try {
+ value = _methods[i].invoke(obj, (Object []) null);
+ } catch (Exception e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeString(_names[i]);
+
+ out.writeObject(value);
+ }
+
+ out.writeMapEnd();
+ }
+ else {
+ if (ref == -1) {
+ out.writeInt(_names.length);
+
+ for (int i = 0; i < _names.length; i++)
+ out.writeString(_names[i]);
+
+ out.writeObjectBegin(cl.getName());
+ }
+
+ for (int i = 0; i < _methods.length; i++) {
+ Method method = _methods[i];
+ Object value = null;
+
+ try {
+ value = _methods[i].invoke(obj, (Object []) null);
+ } catch (Exception e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ out.writeObject(value);
+ }
+ }
+ }
+
+ /**
+ * Finds any matching setter.
+ */
+ private Method findSetter(Method []methods, String getterName, Class arg)
+ {
+ String setterName = "set" + getterName.substring(3);
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (! method.getName().equals(setterName))
+ continue;
+
+ if (! method.getReturnType().equals(void.class))
+ continue;
+
+ Class []params = method.getParameterTypes();
+
+ if (params.length == 1 && params[0].equals(arg))
+ return method;
+ }
+
+ return null;
+ }
+
+ static class MethodNameCmp implements ComparatorHessianInput is unbuffered, so any client needs to provide + * its own buffering. + * + *
+ * InputStream is = ...; // from http connection + * HessianInput in = new HessianInput(is); + * String value; + * + * in.startReply(); // read reply header + * value = in.readString(); // read string value + * in.completeReply(); // read reply footer + *+ */ +public class Hessian2Input + extends AbstractHessianInput + implements Hessian2Constants +{ + private static final Logger log + = Logger.getLogger(Hessian2Input.class.getName()); + + private static final double D_256 = 1.0 / 256.0; + private static final int END_OF_DATA = -2; + + private static Field _detailMessageField; + + private static final int SIZE = 256; + private static final int GAP = 16; + + // factory for deserializing objects in the input stream + protected SerializerFactory _serializerFactory; + + private static boolean _isCloseStreamOnClose; + + protected ArrayList _refs; + protected ArrayList _classDefs; + protected ArrayList _types; + + // the underlying input stream + private InputStream _is; + private final byte []_buffer = new byte[SIZE]; + + // a peek character + private int _offset; + private int _length; + + // true for streaming data + private boolean _isStreaming; + + // the method for a call + private String _method; + private int _argLength; + + private Reader _chunkReader; + private InputStream _chunkInputStream; + + private Throwable _replyFault; + + private StringBuffer _sbuf = new StringBuffer(); + + // true if this is the last chunk + private boolean _isLastChunk; + // the chunk length + private int _chunkLength; + + /** + * Creates a new Hessian input stream, initialized with an + * underlying input stream. + * + * @param is the underlying input stream. + */ + public Hessian2Input(InputStream is) + { + _is = is; + } + + /** + * Sets the serializer factory. + */ + public void setSerializerFactory(SerializerFactory factory) + { + _serializerFactory = factory; + } + + /** + * Gets the serializer factory. + */ + public SerializerFactory getSerializerFactory() + { + return _serializerFactory; + } + + /** + * Gets the serializer factory, creating a default if necessary. + */ + public final SerializerFactory findSerializerFactory() + { + SerializerFactory factory = _serializerFactory; + + if (factory == null) + _serializerFactory = factory = new SerializerFactory(); + + return factory; + } + + public void setCloseStreamOnClose(boolean isClose) + { + _isCloseStreamOnClose = isClose; + } + + public boolean isCloseStreamOnClose() + { + return _isCloseStreamOnClose; + } + + /** + * Returns the calls method + */ + public String getMethod() + { + return _method; + } + + /** + * Returns any reply fault. + */ + public Throwable getReplyFault() + { + return _replyFault; + } + + /** + * Starts reading the call + * + *
+ * c major minor + *+ */ + public int readCall() + throws IOException + { + int tag = read(); + + if (tag != 'C') + throw error("expected hessian call ('C') at " + codeName(tag)); + + return 0; + } + + /** + * Starts reading the envelope + * + *
+ * E major minor + *+ */ + public int readEnvelope() + throws IOException + { + int tag = read(); + int version = 0; + + if (tag == 'H') { + int major = read(); + int minor = read(); + + version = (major << 16) + minor; + + tag = read(); + } + + if (tag != 'E') + throw error("expected hessian Envelope ('E') at " + codeName(tag)); + + return version; + } + + /** + * Completes reading the envelope + * + *
A successful completion will have a single value: + * + *
+ * Z + *+ */ + public void completeEnvelope() + throws IOException + { + int tag = read(); + + if (tag != 'Z') + error("expected end of envelope at " + codeName(tag)); + } + + /** + * Starts reading the call + * + *
A successful completion will have a single value: + * + *
+ * string + *+ */ + public String readMethod() + throws IOException + { + _method = readString(); + + return _method; + } + + /** + * Returns the number of method arguments + * + *
+ * int + *+ */ + @Override + public int readMethodArgLength() + throws IOException + { + return readInt(); + } + + /** + * Starts reading the call, including the headers. + * + *
The call expects the following protocol data + * + *
+ * c major minor + * m b16 b8 method + *+ */ + public void startCall() + throws IOException + { + readCall(); + + readMethod(); + } + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ *+ */ + public void completeCall() + throws IOException + { + } + + /** + * Reads a reply as an object. + * If the reply has a fault, throws the exception. + */ + @Override + public Object readReply(Class expectedClass) + throws Throwable + { + int tag = read(); + + if (tag == 'R') + return readObject(expectedClass); + else if (tag == 'F') { + HashMap map = (HashMap) readObject(HashMap.class); + + throw prepareFault(map); + } + else { + StringBuilder sb = new StringBuilder(); + sb.append((char) tag); + + try { + int ch; + + while ((ch = read()) >= 0) { + sb.append((char) ch); + } + } catch (IOException e) { + log.log(Level.FINE, e.toString(), e); + } + + throw error("expected hessian reply at " + codeName(tag) + "\n" + + sb); + } + } + + /** + * Starts reading the reply + * + *
A successful completion will have a single value: + * + *
+ * r + *+ */ + public void startReply() + throws Throwable + { + // XXX: for variable length (?) + + readReply(Object.class); + } + + /** + * Prepares the fault. + */ + private Throwable prepareFault(HashMap fault) + throws IOException + { + Object detail = fault.get("detail"); + String message = (String) fault.get("message"); + + if (detail instanceof Throwable) { + _replyFault = (Throwable) detail; + + if (message != null && _detailMessageField != null) { + try { + _detailMessageField.set(_replyFault, message); + } catch (Throwable e) { + } + } + + return _replyFault; + } + + else { + String code = (String) fault.get("code"); + + _replyFault = new HessianServiceException(message, code, detail); + + return _replyFault; + } + } + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeReply() + throws IOException + { + } + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeValueReply() + throws IOException + { + int tag = read(); + + if (tag != 'Z') + error("expected end of reply at " + codeName(tag)); + } + + /** + * Reads a header, returning null if there are no headers. + * + *
+ * H b16 b8 value + *+ */ + public String readHeader() + throws IOException + { + return null; + } + + /** + * Starts reading the message + * + *
+ * p major minor + *+ */ + public int startMessage() + throws IOException + { + int tag = read(); + + if (tag == 'p') + _isStreaming = false; + else if (tag == 'P') + _isStreaming = true; + else + throw error("expected Hessian message ('p') at " + codeName(tag)); + + int major = read(); + int minor = read(); + + return (major << 16) + minor; + } + + /** + * Completes reading the message + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeMessage() + throws IOException + { + int tag = read(); + + if (tag != 'Z') + error("expected end of message at " + codeName(tag)); + } + + /** + * Reads a null + * + *
+ * N + *+ */ + public void readNull() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': return; + + default: + throw expect("null", tag); + } + } + + /** + * Reads a boolean + * + *
+ * T + * F + *+ */ + public boolean readBoolean() + throws IOException + { + int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + switch (tag) { + case 'T': return true; + case 'F': return false; + + // direct integer + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return tag != BC_INT_ZERO; + + // INT_BYTE = 0 + case 0xc8: + return read() != 0; + + // INT_BYTE != 0 + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + read(); + return true; + + // INT_SHORT = 0 + case 0xd4: + return (256 * read() + read()) != 0; + + // INT_SHORT != 0 + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd5: case 0xd6: case 0xd7: + read(); + read(); + return true; + + case 'I': return + parseInt() != 0; + + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return tag != BC_LONG_ZERO; + + // LONG_BYTE = 0 + case 0xf8: + return read() != 0; + + // LONG_BYTE != 0 + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + read(); + return true; + + // INT_SHORT = 0 + case 0x3c: + return (256 * read() + read()) != 0; + + // INT_SHORT != 0 + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3d: case 0x3e: case 0x3f: + read(); + read(); + return true; + + case BC_LONG_INT: + return (0x1000000L * read() + + 0x10000L * read() + + 0x100 * read() + + read()) != 0; + + case 'L': + return parseLong() != 0; + + case BC_DOUBLE_ZERO: + return false; + + case BC_DOUBLE_ONE: + return true; + + case BC_DOUBLE_BYTE: + return read() != 0; + + case BC_DOUBLE_SHORT: + return (0x100 * read() + read()) != 0; + + case BC_DOUBLE_MILL: + { + int mills = parseInt(); + + return mills != 0; + } + + case 'D': + return parseDouble() != 0.0; + + case 'N': + return false; + + default: + throw expect("boolean", tag); + } + } + + /** + * Reads a short + * + *
+ * I b32 b24 b16 b8 + *+ */ + public short readShort() + throws IOException + { + return (short) readInt(); + } + + /** + * Reads an integer + * + *
+ * I b32 b24 b16 b8 + *+ */ + public final int readInt() + throws IOException + { + //int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + int tag = read(); + + switch (tag) { + case 'N': + return 0; + + case 'F': + return 0; + + case 'T': + return 1; + + // direct integer + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return tag - BC_INT_ZERO; + + /* byte int */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return ((tag - BC_INT_BYTE_ZERO) << 8) + read(); + + /* short int */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read(); + + case 'I': + case BC_LONG_INT: + return ((read() << 24) + + (read() << 16) + + (read() << 8) + + read()); + + // direct long + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return tag - BC_LONG_ZERO; + + /* byte long */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return ((tag - BC_LONG_BYTE_ZERO) << 8) + read(); + + /* short long */ + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read(); + + case 'L': + return (int) parseLong(); + + case BC_DOUBLE_ZERO: + return 0; + + case BC_DOUBLE_ONE: + return 1; + + //case LONG_BYTE: + case BC_DOUBLE_BYTE: + return (byte) (_offset < _length ? _buffer[_offset++] : read()); + + //case INT_SHORT: + //case LONG_SHORT: + case BC_DOUBLE_SHORT: + return (short) (256 * read() + read()); + + case BC_DOUBLE_MILL: + { + int mills = parseInt(); + + return (int) (0.001 * mills); + } + + case 'D': + return (int) parseDouble(); + + default: + throw expect("integer", tag); + } + } + + /** + * Reads a long + * + *
+ * L b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public long readLong() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return 0; + + case 'F': + return 0; + + case 'T': + return 1; + + // direct integer + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return tag - BC_INT_ZERO; + + /* byte int */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return ((tag - BC_INT_BYTE_ZERO) << 8) + read(); + + /* short int */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read(); + + //case LONG_BYTE: + case BC_DOUBLE_BYTE: + return (byte) (_offset < _length ? _buffer[_offset++] : read()); + + //case INT_SHORT: + //case LONG_SHORT: + case BC_DOUBLE_SHORT: + return (short) (256 * read() + read()); + + case 'I': + case BC_LONG_INT: + return parseInt(); + + // direct long + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return tag - BC_LONG_ZERO; + + /* byte long */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return ((tag - BC_LONG_BYTE_ZERO) << 8) + read(); + + /* short long */ + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read(); + + case 'L': + return parseLong(); + + case BC_DOUBLE_ZERO: + return 0; + + case BC_DOUBLE_ONE: + return 1; + + case BC_DOUBLE_MILL: + { + int mills = parseInt(); + + return (long) (0.001 * mills); + } + + case 'D': + return (long) parseDouble(); + + default: + throw expect("long", tag); + } + } + + /** + * Reads a float + * + *
+ * D b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public float readFloat() + throws IOException + { + return (float) readDouble(); + } + + /** + * Reads a double + * + *
+ * D b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public double readDouble() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return 0; + + case 'F': + return 0; + + case 'T': + return 1; + + // direct integer + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return tag - 0x90; + + /* byte int */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return ((tag - BC_INT_BYTE_ZERO) << 8) + read(); + + /* short int */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read(); + + case 'I': + case BC_LONG_INT: + return parseInt(); + + // direct long + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return tag - BC_LONG_ZERO; + + /* byte long */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return ((tag - BC_LONG_BYTE_ZERO) << 8) + read(); + + /* short long */ + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read(); + + case 'L': + return (double) parseLong(); + + case BC_DOUBLE_ZERO: + return 0; + + case BC_DOUBLE_ONE: + return 1; + + case BC_DOUBLE_BYTE: + return (byte) (_offset < _length ? _buffer[_offset++] : read()); + + case BC_DOUBLE_SHORT: + return (short) (256 * read() + read()); + + case BC_DOUBLE_MILL: + { + int mills = parseInt(); + + return 0.001 * mills; + } + + case 'D': + return parseDouble(); + + default: + throw expect("double", tag); + } + } + + /** + * Reads a date. + * + *
+ * T b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public long readUTCDate() + throws IOException + { + int tag = read(); + + if (tag == BC_DATE) { + return parseLong(); + } + else if (tag == BC_DATE_MINUTE) { + return parseInt() * 60000L; + } + else + throw expect("date", tag); + } + + /** + * Reads a byte from the stream. + */ + public int readChar() + throws IOException + { + if (_chunkLength > 0) { + _chunkLength--; + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + int ch = parseUTF8Char(); + return ch; + } + else if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'S': + case BC_STRING_CHUNK: + _isLastChunk = tag == 'S'; + _chunkLength = (read() << 8) + read(); + + _chunkLength--; + int value = parseUTF8Char(); + + // special code so successive read byte won't + // be read as a single object. + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + return value; + + default: + throw expect("char", tag); + } + } + + /** + * Reads a byte array from the stream. + */ + public int readString(char []buffer, int offset, int length) + throws IOException + { + int readLength = 0; + + if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + else if (_chunkLength == 0) { + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'S': + case BC_STRING_CHUNK: + _isLastChunk = tag == 'S'; + _chunkLength = (read() << 8) + read(); + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + _isLastChunk = true; + _chunkLength = tag - 0x00; + break; + + default: + throw expect("string", tag); + } + } + + while (length > 0) { + if (_chunkLength > 0) { + buffer[offset++] = (char) parseUTF8Char(); + _chunkLength--; + length--; + readLength++; + } + else if (_isLastChunk) { + if (readLength == 0) + return -1; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + else { + int tag = read(); + + switch (tag) { + case 'S': + case BC_STRING_CHUNK: + _isLastChunk = tag == 'S'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("string", tag); + } + } + } + + if (readLength == 0) + return -1; + else if (_chunkLength > 0 || ! _isLastChunk) + return readLength; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + + /** + * Reads a string + * + *
+ * S b16 b8 string value + *+ */ + public String readString() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + case 'T': + return "true"; + case 'F': + return "false"; + + // direct integer + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return String.valueOf((tag - 0x90)); + + /* byte int */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return String.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read()); + + /* short int */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + return String.valueOf(((tag - BC_INT_SHORT_ZERO) << 16) + + 256 * read() + read()); + + case 'I': + case BC_LONG_INT: + return String.valueOf(parseInt()); + + // direct long + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return String.valueOf(tag - BC_LONG_ZERO); + + /* byte long */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return String.valueOf(((tag - BC_LONG_BYTE_ZERO) << 8) + read()); + + /* short long */ + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + return String.valueOf(((tag - BC_LONG_SHORT_ZERO) << 16) + + 256 * read() + read()); + + case 'L': + return String.valueOf(parseLong()); + + case BC_DOUBLE_ZERO: + return "0.0"; + + case BC_DOUBLE_ONE: + return "1.0"; + + case BC_DOUBLE_BYTE: + return String.valueOf((byte) (_offset < _length + ? _buffer[_offset++] + : read())); + + case BC_DOUBLE_SHORT: + return String.valueOf(((short) (256 * read() + read()))); + + case BC_DOUBLE_MILL: + { + int mills = parseInt(); + + return String.valueOf(0.001 * mills); + } + + case 'D': + return String.valueOf(parseDouble()); + + case 'S': + case BC_STRING_CHUNK: + _isLastChunk = tag == 'S'; + _chunkLength = (read() << 8) + read(); + + _sbuf.setLength(0); + int ch; + + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + + // 0-byte string + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + _isLastChunk = true; + _chunkLength = tag - 0x00; + + _sbuf.setLength(0); + + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + + case 0x30: case 0x31: case 0x32: case 0x33: + _isLastChunk = true; + _chunkLength = (tag - 0x30) * 256 + read(); + + _sbuf.setLength(0); + + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + + default: + throw expect("string", tag); + } + } + + /** + * Reads a byte array + * + *
+ * B b16 b8 data value + *+ */ + public byte []readBytes() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'B': + case BC_BINARY_CHUNK: + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + int data; + while ((data = parseByte()) >= 0) + bos.write(data); + + return bos.toByteArray(); + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + { + _isLastChunk = true; + _chunkLength = tag - 0x20; + + byte []buffer = new byte[_chunkLength]; + + int k = 0; + while ((data = parseByte()) >= 0) + buffer[k++] = (byte) data; + + return buffer; + } + + case 0x34: case 0x35: case 0x36: case 0x37: + { + _isLastChunk = true; + _chunkLength = (tag - 0x34) * 256 + read(); + + byte []buffer = new byte[_chunkLength]; + int k = 0; + + while ((data = parseByte()) >= 0) { + buffer[k++] = (byte) data; + } + + return buffer; + } + + default: + throw expect("bytes", tag); + } + } + + /** + * Reads a byte from the stream. + */ + public int readByte() + throws IOException + { + if (_chunkLength > 0) { + _chunkLength--; + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + return read(); + } + else if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'B': + case BC_BINARY_CHUNK: + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + + int value = parseByte(); + + // special code so successive read byte won't + // be read as a single object. + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + return value; + + default: + throw expect("binary", tag); + } + } + + /** + * Reads a byte array from the stream. + */ + public int readBytes(byte []buffer, int offset, int length) + throws IOException + { + int readLength = 0; + + if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + else if (_chunkLength == 0) { + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'B': + case BC_BINARY_CHUNK: + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("binary", tag); + } + } + + while (length > 0) { + if (_chunkLength > 0) { + buffer[offset++] = (byte) read(); + _chunkLength--; + length--; + readLength++; + } + else if (_isLastChunk) { + if (readLength == 0) + return -1; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + else { + int tag = read(); + + switch (tag) { + case 'B': + case BC_BINARY_CHUNK: + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("binary", tag); + } + } + } + + if (readLength == 0) + return -1; + else if (_chunkLength > 0 || ! _isLastChunk) + return readLength; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + + /** + * Reads a fault. + */ + private HashMap readFault() + throws IOException + { + HashMap map = new HashMap(); + + int code = read(); + for (; code > 0 && code != 'Z'; code = read()) { + _offset--; + + Object key = readObject(); + Object value = readObject(); + + if (key != null && value != null) + map.put(key, value); + } + + if (code != 'Z') + throw expect("fault", code); + + return map; + } + + /** + * Reads an object from the input stream with an expected type. + */ + public Object readObject(Class cl) + throws IOException + { + if (cl == null || cl == Object.class) + return readObject(); + + int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + switch (tag) { + case 'N': + return null; + + case 'H': + { + Deserializer reader = findSerializerFactory().getDeserializer(cl); + + return reader.readMap(this); + } + + case 'M': + { + String type = readType(); + + // hessian/3bb3 + if ("".equals(type)) { + Deserializer reader; + reader = findSerializerFactory().getDeserializer(cl); + + return reader.readMap(this); + } + else { + Deserializer reader; + reader = findSerializerFactory().getObjectDeserializer(type, cl); + + return reader.readMap(this); + } + } + + case 'C': + { + readObjectDefinition(cl); + + return readObject(cl); + } + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + { + int ref = tag - 0x60; + int size = _classDefs.size(); + + if (ref < 0 || size <= ref) + throw new HessianProtocolException("'" + ref + "' is an unknown class definition"); + + ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref); + + return readObjectInstance(cl, def); + } + + case 'O': + { + int ref = readInt(); + int size = _classDefs.size(); + + if (ref < 0 || size <= ref) + throw new HessianProtocolException("'" + ref + "' is an unknown class definition"); + + ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref); + + return readObjectInstance(cl, def); + } + + case BC_LIST_VARIABLE: + { + String type = readType(); + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(type, cl); + + Object v = reader.readList(this, -1); + + return v; + } + + case BC_LIST_FIXED: + { + String type = readType(); + int length = readInt(); + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(type, cl); + + Object v = reader.readLengthList(this, length); + + return v; + } + + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + { + int length = tag - 0x70; + + String type = readType(); + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(null, cl); + + Object v = reader.readLengthList(this, length); + + return v; + } + + case BC_LIST_VARIABLE_UNTYPED: + { + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(null, cl); + + Object v = reader.readList(this, -1); + + return v; + } + + case BC_LIST_FIXED_UNTYPED: + { + int length = readInt(); + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(null, cl); + + Object v = reader.readLengthList(this, length); + + return v; + } + + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + int length = tag - 0x78; + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(null, cl); + + Object v = reader.readLengthList(this, length); + + return v; + } + + case BC_REF: + { + int ref = readInt(); + + return _refs.get(ref); + } + } + + if (tag >= 0) + _offset--; + + // hessian/3b2i vs hessian/3406 + // return readObject(); + Object value = findSerializerFactory().getDeserializer(cl).readObject(this); + return value; + } + + /** + * Reads an arbitrary object from the input stream when the type + * is unknown. + */ + public Object readObject() + throws IOException + { + int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + switch (tag) { + case 'N': + return null; + + case 'T': + return Boolean.valueOf(true); + + case 'F': + return Boolean.valueOf(false); + + // direct integer + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + return Integer.valueOf(tag - BC_INT_ZERO); + + /* byte int */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return Integer.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read()); + + /* short int */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + return Integer.valueOf(((tag - BC_INT_SHORT_ZERO) << 16) + + 256 * read() + read()); + + case 'I': + return Integer.valueOf(parseInt()); + + // direct long + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return Long.valueOf(tag - BC_LONG_ZERO); + + /* byte long */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return Long.valueOf(((tag - BC_LONG_BYTE_ZERO) << 8) + read()); + + /* short long */ + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + return Long.valueOf(((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read()); + + case BC_LONG_INT: + return Long.valueOf(parseInt()); + + case 'L': + return Long.valueOf(parseLong()); + + case BC_DOUBLE_ZERO: + return Double.valueOf(0); + + case BC_DOUBLE_ONE: + return Double.valueOf(1); + + case BC_DOUBLE_BYTE: + return Double.valueOf((byte) read()); + + case BC_DOUBLE_SHORT: + return Double.valueOf((short) (256 * read() + read())); + + case BC_DOUBLE_MILL: + { + int mills = parseInt(); + + return Double.valueOf(0.001 * mills); + } + + case 'D': + return Double.valueOf(parseDouble()); + + case BC_DATE: + return new Date(parseLong()); + + case BC_DATE_MINUTE: + return new Date(parseInt() * 60000L); + + case BC_STRING_CHUNK: + case 'S': + { + _isLastChunk = tag == 'S'; + _chunkLength = (read() << 8) + read(); + + int data; + _sbuf.setLength(0); + + while ((data = parseChar()) >= 0) + _sbuf.append((char) data); + + return _sbuf.toString(); + } + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + { + _isLastChunk = true; + _chunkLength = tag - 0x00; + + int data; + _sbuf.setLength(0); + + while ((data = parseChar()) >= 0) + _sbuf.append((char) data); + + return _sbuf.toString(); + } + + case 0x30: case 0x31: case 0x32: case 0x33: + { + _isLastChunk = true; + _chunkLength = (tag - 0x30) * 256 + read(); + + _sbuf.setLength(0); + + int ch; + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + } + + case BC_BINARY_CHUNK: + case 'B': + { + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + + int data; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + while ((data = parseByte()) >= 0) + bos.write(data); + + return bos.toByteArray(); + } + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + { + _isLastChunk = true; + int len = tag - 0x20; + _chunkLength = 0; + + byte []data = new byte[len]; + + for (int i = 0; i < len; i++) + data[i] = (byte) read(); + + return data; + } + + case 0x34: case 0x35: case 0x36: case 0x37: + { + _isLastChunk = true; + int len = (tag - 0x34) * 256 + read(); + _chunkLength = 0; + + byte []buffer = new byte[len]; + + for (int i = 0; i < len; i++) { + buffer[i] = (byte) read(); + } + + return buffer; + } + + case BC_LIST_VARIABLE: + { + // variable length list + String type = readType(); + + return findSerializerFactory().readList(this, -1, type); + } + + case BC_LIST_VARIABLE_UNTYPED: + { + return findSerializerFactory().readList(this, -1, null); + } + + case BC_LIST_FIXED: + { + // fixed length lists + String type = readType(); + int length = readInt(); + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(type, null); + + return reader.readLengthList(this, length); + } + + case BC_LIST_FIXED_UNTYPED: + { + // fixed length lists + int length = readInt(); + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(null, null); + + return reader.readLengthList(this, length); + } + + // compact fixed list + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + { + // fixed length lists + String type = readType(); + int length = tag - 0x70; + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(type, null); + + return reader.readLengthList(this, length); + } + + // compact fixed untyped list + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + // fixed length lists + int length = tag - 0x78; + + Deserializer reader; + reader = findSerializerFactory().getListDeserializer(null, null); + + return reader.readLengthList(this, length); + } + + case 'H': + { + return findSerializerFactory().readMap(this, null); + } + + case 'M': + { + String type = readType(); + + return findSerializerFactory().readMap(this, type); + } + + case 'C': + { + readObjectDefinition(null); + + return readObject(); + } + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + { + int ref = tag - 0x60; + + if (_classDefs == null) + throw error("No classes defined at reference '{0}'" + tag); + + ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref); + + return readObjectInstance(null, def); + } + + case 'O': + { + int ref = readInt(); + + ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref); + + return readObjectInstance(null, def); + } + + case BC_REF: + { + int ref = readInt(); + + return _refs.get(ref); + } + + default: + if (tag < 0) + throw new EOFException("readObject: unexpected end of file"); + else + throw error("readObject: unknown code " + codeName(tag)); + } + } + + /** + * Reads an object definition: + * + *
+ * O string+ */ + private void readObjectDefinition(Class cl) + throws IOException + { + String type = readString(); + int len = readInt(); + + String []fieldNames = new String[len]; + for (int i = 0; i < len; i++) + fieldNames[i] = readString(); + + ObjectDefinition def = new ObjectDefinition(type, fieldNames); + + if (_classDefs == null) + _classDefs = new ArrayList(); + + _classDefs.add(def); + } + + private Object readObjectInstance(Class cl, ObjectDefinition def) + throws IOException + { + String type = def.getType(); + String []fieldNames = def.getFieldNames(); + + if (cl != null) { + Deserializer reader; + reader = findSerializerFactory().getObjectDeserializer(type, cl); + + return reader.readObject(this, fieldNames); + } + else { + return findSerializerFactory().readObject(this, type, fieldNames); + } + } + + private String readLenString() + throws IOException + { + int len = readInt(); + + _isLastChunk = true; + _chunkLength = len; + + _sbuf.setLength(0); + int ch; + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + } + + private String readLenString(int len) + throws IOException + { + _isLastChunk = true; + _chunkLength = len; + + _sbuf.setLength(0); + int ch; + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + } + + /** + * Reads a remote object. + */ + public Object readRemote() + throws IOException + { + String type = readType(); + String url = readString(); + + return resolveRemote(type, url); + } + + /** + * Reads a reference. + */ + public Object readRef() + throws IOException + { + return _refs.get(parseInt()); + } + + /** + * Reads the start of a list. + */ + public int readListStart() + throws IOException + { + return read(); + } + + /** + * Reads the start of a list. + */ + public int readMapStart() + throws IOException + { + return read(); + } + + /** + * Returns true if this is the end of a list or a map. + */ + public boolean isEnd() + throws IOException + { + int code; + + if (_offset < _length) + code = (_buffer[_offset] & 0xff); + else { + code = read(); + + if (code >= 0) + _offset--; + } + + return (code < 0 || code == 'Z'); + } + + /** + * Reads the end byte. + */ + public void readEnd() + throws IOException + { + int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + if (code == 'Z') + return; + else if (code < 0) + throw error("unexpected end of file"); + else + throw error("unknown code:" + codeName(code)); + } + + /** + * Reads the end byte. + */ + public void readMapEnd() + throws IOException + { + int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + if (code != 'Z') + throw error("expected end of map ('Z') at '" + codeName(code) + "'"); + } + + /** + * Reads the end byte. + */ + public void readListEnd() + throws IOException + { + int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + if (code != 'Z') + throw error("expected end of list ('Z') at '" + codeName(code) + "'"); + } + + /** + * Adds a list/map reference. + */ + public int addRef(Object ref) + { + if (_refs == null) + _refs = new ArrayList(); + + _refs.add(ref); + + return _refs.size() - 1; + } + + /** + * Adds a list/map reference. + */ + public void setRef(int i, Object ref) + { + _refs.set(i, ref); + } + + /** + * Resets the references for streaming. + */ + public void resetReferences() + { + if (_refs != null) + _refs.clear(); + } + + public Object readStreamingObject() + throws IOException + { + if (_refs != null) + _refs.clear(); + + return readObject(); + } + + /** + * Resolves a remote object. + */ + public Object resolveRemote(String type, String url) + throws IOException + { + HessianRemoteResolver resolver = getRemoteResolver(); + + if (resolver != null) + return resolver.lookup(type, url); + else + return new HessianRemote(type, url); + } + + /** + * Parses a type from the stream. + * + *(string)* * + *
+ * type ::= string + * type ::= int + *+ */ + public String readType() + throws IOException + { + int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + _offset--; + + switch (code) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + + case 0x30: case 0x31: case 0x32: case 0x33: + case BC_STRING_CHUNK: case 'S': + { + String type = readString(); + + if (_types == null) + _types = new ArrayList(); + + _types.add(type); + + return type; + } + + default: + { + int ref = readInt(); + + if (_types.size() <= ref) + throw new IndexOutOfBoundsException("type ref #" + ref + " is greater than the number of valid types (" + _types.size() + ")"); + + return (String) _types.get(ref); + } + } + } + + /** + * Parses the length for an array + * + *
+ * l b32 b24 b16 b8 + *+ */ + public int readLength() + throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Parses a 32-bit integer value from the stream. + * + *
+ * b32 b24 b16 b8 + *+ */ + private int parseInt() + throws IOException + { + int offset = _offset; + + if (offset + 3 < _length) { + byte []buffer = _buffer; + + int b32 = buffer[offset + 0] & 0xff; + int b24 = buffer[offset + 1] & 0xff; + int b16 = buffer[offset + 2] & 0xff; + int b8 = buffer[offset + 3] & 0xff; + + _offset = offset + 4; + + return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8; + } + else { + int b32 = read(); + int b24 = read(); + int b16 = read(); + int b8 = read(); + + return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8; + } + } + + /** + * Parses a 64-bit long value from the stream. + * + *
+ * b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + private long parseLong() + throws IOException + { + long b64 = read(); + long b56 = read(); + long b48 = read(); + long b40 = read(); + long b32 = read(); + long b24 = read(); + long b16 = read(); + long b8 = read(); + + return ((b64 << 56) + + (b56 << 48) + + (b48 << 40) + + (b40 << 32) + + (b32 << 24) + + (b24 << 16) + + (b16 << 8) + + b8); + } + + /** + * Parses a 64-bit double value from the stream. + * + *
+ * b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + private double parseDouble() + throws IOException + { + long bits = parseLong(); + + return Double.longBitsToDouble(bits); + } + + org.w3c.dom.Node parseXML() + throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Reads a character from the underlying stream. + */ + private int parseChar() + throws IOException + { + while (_chunkLength <= 0) { + if (_isLastChunk) + return -1; + + int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + switch (code) { + case BC_STRING_CHUNK: + _isLastChunk = false; + + _chunkLength = (read() << 8) + read(); + break; + + case 'S': + _isLastChunk = true; + + _chunkLength = (read() << 8) + read(); + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + _isLastChunk = true; + _chunkLength = code - 0x00; + break; + + // qian.lei 2010-7-21 + case 0x30: case 0x31: case 0x32: case 0x33: + _isLastChunk = true; + _chunkLength = ((code - 0x30) << 8) + read(); + break; + + default: + throw expect("string", code); + } + + } + + _chunkLength--; + + return parseUTF8Char(); + } + + /** + * Parses a single UTF8 character. + */ + private int parseUTF8Char() + throws IOException + { + int ch = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); + + if (ch < 0x80) + return ch; + else if ((ch & 0xe0) == 0xc0) { + int ch1 = read(); + int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f); + + return v; + } + else if ((ch & 0xf0) == 0xe0) { + int ch1 = read(); + int ch2 = read(); + int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f); + + return v; + } + else + throw error("bad utf-8 encoding at " + codeName(ch)); + } + + /** + * Reads a byte from the underlying stream. + */ + private int parseByte() + throws IOException + { + while (_chunkLength <= 0) { + if (_isLastChunk) { + return -1; + } + + int code = read(); + + switch (code) { + case BC_BINARY_CHUNK: + _isLastChunk = false; + + _chunkLength = (read() << 8) + read(); + break; + + case 'B': + _isLastChunk = true; + + _chunkLength = (read() << 8) + read(); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + _isLastChunk = true; + + _chunkLength = code - 0x20; + break; + + case 0x34: case 0x35: case 0x36: case 0x37: + _isLastChunk = true; + _chunkLength = (code - 0x34) * 256 + read(); + break; + + default: + throw expect("byte[]", code); + } + } + + _chunkLength--; + + return read(); + } + + /** + * Reads bytes based on an input stream. + */ + public InputStream readInputStream() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'B': + case 'b': + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + _isLastChunk = true; + _chunkLength = tag - 0x20; + break; + + default: + throw expect("binary", tag); + } + + return new ReadInputStream(); + } + + /** + * Reads bytes from the underlying stream. + */ + int read(byte []buffer, int offset, int length) + throws IOException + { + int readLength = 0; + + while (length > 0) { + while (_chunkLength <= 0) { + if (_isLastChunk) + return readLength == 0 ? -1 : readLength; + + int code = read(); + + switch (code) { + case 'b': + _isLastChunk = false; + + _chunkLength = (read() << 8) + read(); + break; + + case 'B': + _isLastChunk = true; + + _chunkLength = (read() << 8) + read(); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + _isLastChunk = true; + _chunkLength = code - 0x20; + break; + + default: + throw expect("byte[]", code); + } + } + + int sublen = _chunkLength; + if (length < sublen) + sublen = length; + + if (_length <= _offset && ! readBuffer()) + return -1; + + if (_length - _offset < sublen) + sublen = _length - _offset; + + System.arraycopy(_buffer, _offset, buffer, offset, sublen); + + _offset += sublen; + + offset += sublen; + readLength += sublen; + length -= sublen; + _chunkLength -= sublen; + } + + return readLength; + } + + /** + * Normally, shouldn't be called externally, but needed for QA, e.g. + * ejb/3b01. + */ + public final int read() + throws IOException + { + if (_length <= _offset && ! readBuffer()) + return -1; + + return _buffer[_offset++] & 0xff; + } + + private final boolean readBuffer() + throws IOException + { + byte []buffer = _buffer; + int offset = _offset; + int length = _length; + + if (offset < length) { + System.arraycopy(buffer, offset, buffer, 0, length - offset); + offset = length - offset; + } + else + offset = 0; + + int len = _is.read(buffer, offset, SIZE - offset); + + if (len <= 0) { + _length = offset; + _offset = 0; + + return offset > 0; + } + + _length = offset + len; + _offset = 0; + + return true; + } + + public Reader getReader() + { + return null; + } + + protected IOException expect(String expect, int ch) + throws IOException + { + if (ch < 0) + return error("expected " + expect + " at end of file"); + else { + _offset--; + + try { + Object obj = readObject(); + + if (obj != null) { + return error("expected " + expect + + " at 0x" + Integer.toHexString(ch & 0xff) + + " " + obj.getClass().getName() + " (" + obj + ")"); + } + else + return error("expected " + expect + + " at 0x" + Integer.toHexString(ch & 0xff) + " null"); + } catch (IOException e) { + log.log(Level.FINE, e.toString(), e); + + return error("expected " + expect + + " at 0x" + Integer.toHexString(ch & 0xff)); + } + } + } + + protected String codeName(int ch) + { + if (ch < 0) + return "end of file"; + else + return "0x" + Integer.toHexString(ch & 0xff) + " (" + (char) + ch + ")"; + } + + protected IOException error(String message) + { + if (_method != null) + return new HessianProtocolException(_method + ": " + message); + else + return new HessianProtocolException(message); + } + + public void close() + throws IOException + { + InputStream is = _is; + _is = null; + + if (_isCloseStreamOnClose && is != null) + is.close(); + } + + class ReadInputStream extends InputStream { + boolean _isClosed = false; + + public int read() + throws IOException + { + if (_isClosed) + return -1; + + int ch = parseByte(); + if (ch < 0) + _isClosed = true; + + return ch; + } + + public int read(byte []buffer, int offset, int length) + throws IOException + { + if (_isClosed) + return -1; + + int len = Hessian2Input.this.read(buffer, offset, length); + if (len < 0) + _isClosed = true; + + return len; + } + + public void close() + throws IOException + { + while (read() >= 0) { + } + } + }; + + final static class ObjectDefinition { + private final String _type; + private final String []_fields; + + ObjectDefinition(String type, String []fields) + { + _type = type; + _fields = fields; + } + + String getType() + { + return _type; + } + + String []getFieldNames() + { + return _fields; + } + } + + static { + try { + _detailMessageField = Throwable.class.getDeclaredField("detailMessage"); + _detailMessageField.setAccessible(true); + } catch (Throwable e) { + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java new file mode 100644 index 0000000000..657d4d2edd --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java @@ -0,0 +1,1605 @@ +/* + * 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 "Burlap", "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.alibaba.com.caucho.hessian.io; + +import com.alibaba.com.caucho.hessian.util.IdentityIntMap; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; + +/** + * Output stream for Hessian 2 requests. + * + *
Since HessianOutput does not depend on any classes other than + * in the JDK, it can be extracted independently into a smaller package. + * + *
HessianOutput is unbuffered, so any client needs to provide + * its own buffering. + * + *
+ * OutputStream os = ...; // from http connection
+ * Hessian2Output out = new Hessian2Output(os);
+ * String value;
+ *
+ * out.startCall("hello", 1); // start hello call
+ * out.writeString("arg1"); // write a string argument
+ * out.completeCall(); // complete the call
+ *
+ */
+public class Hessian2Output
+ extends AbstractHessianOutput
+ implements Hessian2Constants
+{
+ // the output stream/
+ protected OutputStream _os;
+
+ // map of references
+ private IdentityIntMap _refs = new IdentityIntMap();
+
+ private boolean _isCloseStreamOnClose;
+
+ // map of classes
+ private HashMap _classRefs;
+
+ // map of types
+ private HashMap _typeRefs;
+
+ public final static int SIZE = 4096;
+
+ private final byte []_buffer = new byte[SIZE];
+ private int _offset;
+
+ private boolean _isStreaming;
+
+ /**
+ * Creates a new Hessian output stream, initialized with an
+ * underlying output stream.
+ *
+ * @param os the underlying output stream.
+ */
+ public Hessian2Output(OutputStream os)
+ {
+ _os = os;
+ }
+
+ public void setCloseStreamOnClose(boolean isClose)
+ {
+ _isCloseStreamOnClose = isClose;
+ }
+
+ public boolean isCloseStreamOnClose()
+ {
+ return _isCloseStreamOnClose;
+ }
+
+
+ /**
+ * Writes a complete method call.
+ */
+ @Override
+ public void call(String method, Object []args)
+ throws IOException
+ {
+ int length = args != null ? args.length : 0;
+
+ startCall(method, length);
+
+ for (int i = 0; i < args.length; i++)
+ writeObject(args[i]);
+
+ completeCall();
+ }
+
+ /**
+ * Starts the method call. Clients would use startCall
+ * instead of call if they wanted finer control over
+ * writing the arguments, or needed to write headers.
+ *
+ *
+ * C
+ * string # method name
+ * int # arg count
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startCall(String method, int length)
+ throws IOException
+ {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ flush();
+ offset = _offset;
+ }
+
+ byte []buffer = _buffer;
+
+ buffer[_offset++] = (byte) 'C';
+
+ writeString(method);
+ writeInt(length);
+ }
+
+ /**
+ * Writes the call tag. This would be followed by the
+ * method and the arguments
+ *
+ *
+ * C
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startCall()
+ throws IOException
+ {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'C';
+ }
+
+ /**
+ * Starts an envelope.
+ *
+ *
+ * E major minor
+ * m b16 b8 method-name
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startEnvelope(String method)
+ throws IOException
+ {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ flush();
+ offset = _offset;
+ }
+
+ _buffer[_offset++] = (byte) 'E';
+
+ writeString(method);
+ }
+
+ /**
+ * Completes an envelope.
+ *
+ * A successful completion will have a single value: + * + *
+ * Z + *+ */ + public void completeEnvelope() + throws IOException + { + flushIfFull(); + + _buffer[_offset++] = (byte) 'Z'; + } + + /** + * Writes the method tag. + * + *
+ * string
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void writeMethod(String method)
+ throws IOException
+ {
+ writeString(method);
+ }
+
+ /**
+ * Completes.
+ *
+ *
+ * z
+ *
+ */
+ public void completeCall()
+ throws IOException
+ {
+ /*
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'Z';
+ */
+ }
+
+ /**
+ * Starts the reply
+ *
+ * A successful completion will have a single value: + * + *
+ * R + *+ */ + public void startReply() + throws IOException + { + writeVersion(); + + flushIfFull(); + + _buffer[_offset++] = (byte) 'R'; + } + + public void writeVersion() + throws IOException + { + flushIfFull(); + _buffer[_offset++] = (byte) 'H'; + _buffer[_offset++] = (byte) 2; + _buffer[_offset++] = (byte) 0; + } + + /** + * Completes reading the reply + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeReply() + throws IOException + { + } + + /** + * Starts a packet + * + *
A message contains several objects encapsulated by a length
+ * + *+ * p x02 x00 + *+ */ + public void startMessage() + throws IOException + { + flushIfFull(); + + _buffer[_offset++] = (byte) 'p'; + _buffer[_offset++] = (byte) 2; + _buffer[_offset++] = (byte) 0; + } + + /** + * Completes reading the message + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeMessage() + throws IOException + { + flushIfFull(); + + _buffer[_offset++] = (byte) 'z'; + } + + /** + * Writes a fault. The fault will be written + * as a descriptive string followed by an object: + * + *
+ * F map
+ *
+ *
+ *
+ * F H
+ * \x04code
+ * \x10the fault code
+ *
+ * \x07message
+ * \x11the fault message
+ *
+ * \x06detail
+ * M\xnnjavax.ejb.FinderException
+ * ...
+ * Z
+ * Z
+ *
+ *
+ * @param code the fault code, a three digit
+ */
+ public void writeFault(String code, String message, Object detail)
+ throws IOException
+ {
+ flushIfFull();
+
+ writeVersion();
+
+ _buffer[_offset++] = (byte) 'F';
+ _buffer[_offset++] = (byte) 'H';
+
+ _refs.put(new HashMap(), _refs.size());
+
+ writeString("code");
+ writeString(code);
+
+ writeString("message");
+ writeString(message);
+
+ if (detail != null) {
+ writeString("detail");
+ writeObject(detail);
+ }
+
+ flushIfFull();
+ _buffer[_offset++] = (byte) 'Z';
+ }
+
+ /**
+ * Writes any object to the output stream.
+ */
+ public void writeObject(Object object)
+ throws IOException
+ {
+ if (object == null) {
+ writeNull();
+ return;
+ }
+
+ Serializer serializer;
+
+ serializer = findSerializerFactory().getSerializer(object.getClass());
+
+ serializer.writeObject(object, this);
+ }
+
+ /**
+ * Writes the list header to the stream. List writers will call
+ * writeListBegin followed by the list contents and then
+ * call writeListEnd.
+ *
+ *
+ * list ::= V type value* Z
+ * ::= v type int value*
+ *
+ *
+ * @return true for variable lists, false for fixed lists
+ */
+ public boolean writeListBegin(int length, String type)
+ throws IOException
+ {
+ flushIfFull();
+
+ if (length < 0) {
+ if (type != null) {
+ _buffer[_offset++] = (byte) BC_LIST_VARIABLE;
+ writeType(type);
+ }
+ else
+ _buffer[_offset++] = (byte) BC_LIST_VARIABLE_UNTYPED;
+
+ return true;
+ }
+ else if (length <= LIST_DIRECT_MAX) {
+ if (type != null) {
+ _buffer[_offset++] = (byte) (BC_LIST_DIRECT + length);
+ writeType(type);
+ }
+ else {
+ _buffer[_offset++] = (byte) (BC_LIST_DIRECT_UNTYPED + length);
+ }
+
+ return false;
+ }
+ else {
+ if (type != null) {
+ _buffer[_offset++] = (byte) BC_LIST_FIXED;
+ writeType(type);
+ }
+ else {
+ _buffer[_offset++] = (byte) BC_LIST_FIXED_UNTYPED;
+ }
+
+ writeInt(length);
+
+ return false;
+ }
+ }
+
+ /**
+ * Writes the tail of the list to the stream for a variable-length list.
+ */
+ public void writeListEnd()
+ throws IOException
+ {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) BC_END;
+ }
+
+ /**
+ * Writes the map header to the stream. Map writers will call
+ * writeMapBegin followed by the map contents and then
+ * call writeMapEnd.
+ *
+ *
+ * map ::= M type ( )* Z
+ * ::= H ( )* Z
+ *
+ */
+ public void writeMapBegin(String type)
+ throws IOException
+ {
+ if (SIZE < _offset + 32)
+ flush();
+
+ if (type != null) {
+ _buffer[_offset++] = BC_MAP;
+
+ writeType(type);
+ }
+ else
+ _buffer[_offset++] = BC_MAP_UNTYPED;
+ }
+
+ /**
+ * Writes the tail of the map to the stream.
+ */
+ public void writeMapEnd()
+ throws IOException
+ {
+ if (SIZE < _offset + 32)
+ flush();
+
+ _buffer[_offset++] = (byte) BC_END;
+ }
+
+ /**
+ * Writes the object definition
+ *
+ *
+ * C <string> <int> <string>*
+ *
+ */
+ public int writeObjectBegin(String type)
+ throws IOException
+ {
+ if (_classRefs == null)
+ _classRefs = new HashMap();
+
+ Integer refV = (Integer) _classRefs.get(type);
+
+ if (refV != null) {
+ int ref = refV.intValue();
+
+ if (SIZE < _offset + 32)
+ flush();
+
+ if (ref <= OBJECT_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
+ }
+ else {
+ _buffer[_offset++] = (byte) 'O';
+ writeInt(ref);
+ }
+
+ return ref;
+ }
+ else {
+ int ref = _classRefs.size();
+
+ _classRefs.put(type, Integer.valueOf(ref));
+
+ if (SIZE < _offset + 32)
+ flush();
+
+ _buffer[_offset++] = (byte) 'C';
+
+ writeString(type);
+
+ return -1;
+ }
+ }
+
+ /**
+ * Writes the tail of the class definition to the stream.
+ */
+ public void writeClassFieldLength(int len)
+ throws IOException
+ {
+ writeInt(len);
+ }
+
+ /**
+ * Writes the tail of the object definition to the stream.
+ */
+ public void writeObjectEnd()
+ throws IOException
+ {
+ }
+
+ /**
+ *
+ * type ::= string
+ * ::= int
+ *
+ */
+ private void writeType(String type)
+ throws IOException
+ {
+ flushIfFull();
+
+ int len = type.length();
+ if (len == 0) {
+ throw new IllegalArgumentException("empty type is not allowed");
+ }
+
+ if (_typeRefs == null)
+ _typeRefs = new HashMap();
+
+ Integer typeRefV = (Integer) _typeRefs.get(type);
+
+ if (typeRefV != null) {
+ int typeRef = typeRefV.intValue();
+
+ writeInt(typeRef);
+ }
+ else {
+ _typeRefs.put(type, Integer.valueOf(_typeRefs.size()));
+
+ writeString(type);
+ }
+ }
+
+ /**
+ * Writes a boolean value to the stream. The boolean will be written
+ * with the following syntax:
+ *
+ *
+ * T
+ * F
+ *
+ *
+ * @param value the boolean value to write.
+ */
+ public void writeBoolean(boolean value)
+ throws IOException
+ {
+ if (SIZE < _offset + 16)
+ flush();
+
+ if (value)
+ _buffer[_offset++] = (byte) 'T';
+ else
+ _buffer[_offset++] = (byte) 'F';
+ }
+
+ /**
+ * Writes an integer value to the stream. The integer will be written
+ * with the following syntax:
+ *
+ *
+ * I b32 b24 b16 b8
+ *
+ *
+ * @param value the integer value to write.
+ */
+ public void writeInt(int value)
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX)
+ buffer[offset++] = (byte) (value + BC_INT_ZERO);
+ else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) {
+ buffer[offset++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8));
+ buffer[offset++] = (byte) (value);
+ }
+ else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) {
+ buffer[offset++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16));
+ buffer[offset++] = (byte) (value >> 8);
+ buffer[offset++] = (byte) (value);
+ }
+ else {
+ buffer[offset++] = (byte) ('I');
+ buffer[offset++] = (byte) (value >> 24);
+ buffer[offset++] = (byte) (value >> 16);
+ buffer[offset++] = (byte) (value >> 8);
+ buffer[offset++] = (byte) (value);
+ }
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a long value to the stream. The long will be written
+ * with the following syntax:
+ *
+ *
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param value the long value to write.
+ */
+ public void writeLong(long value)
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (LONG_DIRECT_MIN <= value && value <= LONG_DIRECT_MAX) {
+ buffer[offset++] = (byte) (value + BC_LONG_ZERO);
+ }
+ else if (LONG_BYTE_MIN <= value && value <= LONG_BYTE_MAX) {
+ buffer[offset++] = (byte) (BC_LONG_BYTE_ZERO + (value >> 8));
+ buffer[offset++] = (byte) (value);
+ }
+ else if (LONG_SHORT_MIN <= value && value <= LONG_SHORT_MAX) {
+ buffer[offset++] = (byte) (BC_LONG_SHORT_ZERO + (value >> 16));
+ buffer[offset++] = (byte) (value >> 8);
+ buffer[offset++] = (byte) (value);
+ }
+ else if (-0x80000000L <= value && value <= 0x7fffffffL) {
+ buffer[offset + 0] = (byte) BC_LONG_INT;
+ buffer[offset + 1] = (byte) (value >> 24);
+ buffer[offset + 2] = (byte) (value >> 16);
+ buffer[offset + 3] = (byte) (value >> 8);
+ buffer[offset + 4] = (byte) (value);
+
+ offset += 5;
+ }
+ else {
+ buffer[offset + 0] = (byte) 'L';
+ buffer[offset + 1] = (byte) (value >> 56);
+ buffer[offset + 2] = (byte) (value >> 48);
+ buffer[offset + 3] = (byte) (value >> 40);
+ buffer[offset + 4] = (byte) (value >> 32);
+ buffer[offset + 5] = (byte) (value >> 24);
+ buffer[offset + 6] = (byte) (value >> 16);
+ buffer[offset + 7] = (byte) (value >> 8);
+ buffer[offset + 8] = (byte) (value);
+
+ offset += 9;
+ }
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a double value to the stream. The double will be written
+ * with the following syntax:
+ *
+ *
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param value the double value to write.
+ */
+ public void writeDouble(double value)
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ int intValue = (int) value;
+
+ if (intValue == value) {
+ if (intValue == 0) {
+ buffer[offset++] = (byte) BC_DOUBLE_ZERO;
+
+ _offset = offset;
+
+ return;
+ }
+ else if (intValue == 1) {
+ buffer[offset++] = (byte) BC_DOUBLE_ONE;
+
+ _offset = offset;
+
+ return;
+ }
+ else if (-0x80 <= intValue && intValue < 0x80) {
+ buffer[offset++] = (byte) BC_DOUBLE_BYTE;
+ buffer[offset++] = (byte) intValue;
+
+ _offset = offset;
+
+ return;
+ }
+ else if (-0x8000 <= intValue && intValue < 0x8000) {
+ buffer[offset + 0] = (byte) BC_DOUBLE_SHORT;
+ buffer[offset + 1] = (byte) (intValue >> 8);
+ buffer[offset + 2] = (byte) intValue;
+
+ _offset = offset + 3;
+
+ return;
+ }
+ }
+
+ int mills = (int) (value * 1000);
+
+ if (0.001 * mills == value) {
+ buffer[offset + 0] = (byte) (BC_DOUBLE_MILL);
+ buffer[offset + 1] = (byte) (mills >> 24);
+ buffer[offset + 2] = (byte) (mills >> 16);
+ buffer[offset + 3] = (byte) (mills >> 8);
+ buffer[offset + 4] = (byte) (mills);
+
+ _offset = offset + 5;
+
+ return;
+ }
+
+ long bits = Double.doubleToLongBits(value);
+
+ buffer[offset + 0] = (byte) 'D';
+ buffer[offset + 1] = (byte) (bits >> 56);
+ buffer[offset + 2] = (byte) (bits >> 48);
+ buffer[offset + 3] = (byte) (bits >> 40);
+ buffer[offset + 4] = (byte) (bits >> 32);
+ buffer[offset + 5] = (byte) (bits >> 24);
+ buffer[offset + 6] = (byte) (bits >> 16);
+ buffer[offset + 7] = (byte) (bits >> 8);
+ buffer[offset + 8] = (byte) (bits);
+
+ _offset = offset + 9;
+ }
+
+ /**
+ * Writes a date to the stream.
+ *
+ *
+ * date ::= d b7 b6 b5 b4 b3 b2 b1 b0
+ * ::= x65 b3 b2 b1 b0
+ *
+ *
+ * @param time the date in milliseconds from the epoch in UTC
+ */
+ public void writeUTCDate(long time)
+ throws IOException
+ {
+ if (SIZE < _offset + 32)
+ flush();
+
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (time % 60000L == 0) {
+ // compact date ::= x65 b3 b2 b1 b0
+
+ long minutes = time / 60000L;
+
+ if ((minutes >> 31) == 0 || (minutes >> 31) == -1) {
+ buffer[offset++] = (byte) BC_DATE_MINUTE;
+ buffer[offset++] = ((byte) (minutes >> 24));
+ buffer[offset++] = ((byte) (minutes >> 16));
+ buffer[offset++] = ((byte) (minutes >> 8));
+ buffer[offset++] = ((byte) (minutes >> 0));
+
+ _offset = offset;
+ return;
+ }
+ }
+
+ buffer[offset++] = (byte) BC_DATE;
+ buffer[offset++] = ((byte) (time >> 56));
+ buffer[offset++] = ((byte) (time >> 48));
+ buffer[offset++] = ((byte) (time >> 40));
+ buffer[offset++] = ((byte) (time >> 32));
+ buffer[offset++] = ((byte) (time >> 24));
+ buffer[offset++] = ((byte) (time >> 16));
+ buffer[offset++] = ((byte) (time >> 8));
+ buffer[offset++] = ((byte) (time));
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a null value to the stream.
+ * The null will be written with the following syntax
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeNull()
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ buffer[offset++] = 'N';
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeString(String value)
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (value == null) {
+ buffer[offset++] = (byte) 'N';
+
+ _offset = offset;
+ }
+ else {
+ int length = value.length();
+ int strOffset = 0;
+
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ offset = _offset;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ // chunk can't end in high surrogate
+ char tail = value.charAt(strOffset + sublen - 1);
+
+ if (0xd800 <= tail && tail <= 0xdbff)
+ sublen--;
+
+ buffer[offset + 0] = (byte) BC_STRING_CHUNK;
+ buffer[offset + 1] = (byte) (sublen >> 8);
+ buffer[offset + 2] = (byte) (sublen);
+
+ _offset = offset + 3;
+
+ printString(value, strOffset, sublen);
+
+ length -= sublen;
+ strOffset += sublen;
+ }
+
+ offset = _offset;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (length <= STRING_DIRECT_MAX) {
+ buffer[offset++] = (byte) (BC_STRING_DIRECT + length);
+ }
+ else if (length <= STRING_SHORT_MAX) {
+ buffer[offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
+ buffer[offset++] = (byte) (length);
+ }
+ else {
+ buffer[offset++] = (byte) ('S');
+ buffer[offset++] = (byte) (length >> 8);
+ buffer[offset++] = (byte) (length);
+ }
+
+ _offset = offset;
+
+ printString(value, strOffset, length);
+ }
+ }
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeString(char []buffer, int offset, int length)
+ throws IOException
+ {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flush();
+
+ _buffer[_offset++] = (byte) ('N');
+ }
+ else {
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ if (SIZE < _offset + 16)
+ flush();
+
+ // chunk can't end in high surrogate
+ char tail = buffer[offset + sublen - 1];
+
+ if (0xd800 <= tail && tail <= 0xdbff)
+ sublen--;
+
+ _buffer[_offset++] = (byte) BC_STRING_CHUNK;
+ _buffer[_offset++] = (byte) (sublen >> 8);
+ _buffer[_offset++] = (byte) (sublen);
+
+ printString(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+
+ if (SIZE < _offset + 16)
+ flush();
+
+ if (length <= STRING_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_STRING_DIRECT + length);
+ }
+ else if (length <= STRING_SHORT_MAX) {
+ _buffer[_offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
+ _buffer[_offset++] = (byte) length;
+ }
+ else {
+ _buffer[_offset++] = (byte) ('S');
+ _buffer[_offset++] = (byte) (length >> 8);
+ _buffer[_offset++] = (byte) (length);
+ }
+
+ printString(buffer, offset, length);
+ }
+ }
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeBytes(byte []buffer)
+ throws IOException
+ {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flush();
+
+ _buffer[_offset++] = 'N';
+ }
+ else
+ writeBytes(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeBytes(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ _buffer[_offset++] = (byte) 'N';
+ }
+ else {
+ flush();
+
+ while (SIZE - _offset - 3 < length) {
+ int sublen = SIZE - _offset - 3;
+
+ if (sublen < 16) {
+ flushBuffer();
+
+ sublen = SIZE - _offset - 3;
+
+ if (length < sublen)
+ sublen = length;
+ }
+
+ _buffer[_offset++] = (byte) BC_BINARY_CHUNK;
+ _buffer[_offset++] = (byte) (sublen >> 8);
+ _buffer[_offset++] = (byte) sublen;
+
+ System.arraycopy(buffer, offset, _buffer, _offset, sublen);
+ _offset += sublen;
+
+ length -= sublen;
+ offset += sublen;
+
+ flushBuffer();
+ }
+
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ if (length <= BINARY_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_BINARY_DIRECT + length);
+ }
+ else if (length <= BINARY_SHORT_MAX) {
+ _buffer[_offset++] = (byte) (BC_BINARY_SHORT + (length >> 8));
+ _buffer[_offset++] = (byte) (length);
+ }
+ else {
+ _buffer[_offset++] = (byte) 'B';
+ _buffer[_offset++] = (byte) (length >> 8);
+ _buffer[_offset++] = (byte) (length);
+ }
+
+ System.arraycopy(buffer, offset, _buffer, _offset, length);
+
+ _offset += length;
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ *
+ */
+ public void writeByteBufferStart()
+ throws IOException
+ {
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ */
+ public void writeByteBufferPart(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ while (length > 0) {
+ int sublen = length;
+
+ if (0x8000 < sublen)
+ sublen = 0x8000;
+
+ flush(); // bypass buffer
+
+ _os.write(BC_BINARY_CHUNK);
+ _os.write(sublen >> 8);
+ _os.write(sublen);
+
+ _os.write(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ */
+ public void writeByteBufferEnd(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ writeBytes(buffer, offset, length);
+ }
+
+ /**
+ * Returns an output stream to write binary data.
+ */
+ public OutputStream getBytesOutputStream()
+ throws IOException
+ {
+ return new BytesOutputStream();
+ }
+
+ /**
+ * Writes a reference.
+ *
+ *
+ * x51 <int>
+ *
+ *
+ * @param value the integer value to write.
+ */
+ @Override
+ protected void writeRef(int value)
+ throws IOException
+ {
+ if (SIZE < _offset + 16)
+ flush();
+
+ _buffer[_offset++] = (byte) BC_REF;
+
+ writeInt(value);
+ }
+
+ /**
+ * If the object has already been written, just write its ref.
+ *
+ * @return true if we're writing a ref.
+ */
+ public boolean addRef(Object object)
+ throws IOException
+ {
+ int ref = _refs.get(object);
+
+ if (ref >= 0) {
+ writeRef(ref);
+
+ return true;
+ }
+ else {
+ _refs.put(object, _refs.size());
+
+ return false;
+ }
+ }
+
+ /**
+ * Removes a reference.
+ */
+ public boolean removeRef(Object obj)
+ throws IOException
+ {
+ if (_refs != null) {
+ _refs.remove(obj);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Replaces a reference from one object to another.
+ */
+ public boolean replaceRef(Object oldRef, Object newRef)
+ throws IOException
+ {
+ Integer value = (Integer) _refs.remove(oldRef);
+
+ if (value != null) {
+ _refs.put(newRef, value);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Resets the references for streaming.
+ */
+ public void resetReferences()
+ {
+ if (_refs != null)
+ _refs.clear();
+ }
+
+ /**
+ * Starts the streaming message
+ *
+ * A streaming message starts with 'P'
+ * + *+ * P x02 x00 + *+ */ + public void writeStreamingObject(Object obj) + throws IOException + { + startStreamingPacket(); + + writeObject(obj); + + endStreamingPacket(); + } + + /** + * Starts a streaming packet + * + *
A streaming message starts with 'P'
+ * + *+ * P x02 x00 + *+ */ + public void startStreamingPacket() + throws IOException + { + if (_refs != null) + _refs.clear(); + + flush(); + + _isStreaming = true; + _offset = 3; + } + + public void endStreamingPacket() + throws IOException + { + int len = _offset - 3; + + _buffer[0] = (byte) 'P'; + _buffer[1] = (byte) (len >> 8); + _buffer[2] = (byte) len; + + _isStreaming = false; + + flush(); + } + + /** + * Prints a string to the stream, encoded as UTF-8 with preceeding length + * + * @param v the string to print. + */ + public void printLenString(String v) + throws IOException + { + if (SIZE < _offset + 16) + flush(); + + if (v == null) { + _buffer[_offset++] = (byte) (0); + _buffer[_offset++] = (byte) (0); + } + else { + int len = v.length(); + _buffer[_offset++] = (byte) (len >> 8); + _buffer[_offset++] = (byte) (len); + + printString(v, 0, len); + } + } + + /** + * Prints a string to the stream, encoded as UTF-8 + * + * @param v the string to print. + */ + public void printString(String v) + throws IOException + { + printString(v, 0, v.length()); + } + + /** + * Prints a string to the stream, encoded as UTF-8 + * + * @param v the string to print. + */ + public void printString(String v, int strOffset, int length) + throws IOException + { + int offset = _offset; + byte []buffer = _buffer; + + for (int i = 0; i < length; i++) { + if (SIZE <= offset + 16) { + _offset = offset; + flush(); + offset = _offset; + } + + char ch = v.charAt(i + strOffset); + + if (ch < 0x80) + buffer[offset++] = (byte) (ch); + else if (ch < 0x800) { + buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f)); + buffer[offset++] = (byte) (0x80 + (ch & 0x3f)); + } + else { + buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf)); + buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f)); + buffer[offset++] = (byte) (0x80 + (ch & 0x3f)); + } + } + + _offset = offset; + } + + /** + * Prints a string to the stream, encoded as UTF-8 + * + * @param v the string to print. + */ + public void printString(char []v, int strOffset, int length) + throws IOException + { + int offset = _offset; + byte []buffer = _buffer; + + for (int i = 0; i < length; i++) { + if (SIZE <= offset + 16) { + _offset = offset; + flush(); + offset = _offset; + } + + char ch = v[i + strOffset]; + + if (ch < 0x80) + buffer[offset++] = (byte) (ch); + else if (ch < 0x800) { + buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f)); + buffer[offset++] = (byte) (0x80 + (ch & 0x3f)); + } + else { + buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf)); + buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f)); + buffer[offset++] = (byte) (0x80 + (ch & 0x3f)); + } + } + + _offset = offset; + } + + private final void flushIfFull() + throws IOException + { + int offset = _offset; + + if (SIZE < offset + 32) { + _offset = 0; + _os.write(_buffer, 0, offset); + } + } + + public final void flush() + throws IOException + { + flushBuffer(); + + if (_os != null) + _os.flush(); + } + + public final void flushBuffer() + throws IOException + { + int offset = _offset; + + if (! _isStreaming && offset > 0) { + _offset = 0; + + _os.write(_buffer, 0, offset); + } + else if (_isStreaming && offset > 3) { + int len = offset - 3; + _buffer[0] = 'p'; + _buffer[1] = (byte) (len >> 8); + _buffer[2] = (byte) len; + _offset = 3; + + _os.write(_buffer, 0, offset); + } + } + + public final void close() + throws IOException + { + // hessian/3a8c + flush(); + + OutputStream os = _os; + _os = null; + + if (os != null) { + if (_isCloseStreamOnClose) + os.close(); + } + } + + class BytesOutputStream extends OutputStream { + private int _startOffset; + + BytesOutputStream() + throws IOException + { + if (SIZE < _offset + 16) { + Hessian2Output.this.flush(); + } + + _startOffset = _offset; + _offset += 3; // skip 'b' xNN xNN + } + + @Override + public void write(int ch) + throws IOException + { + if (SIZE <= _offset) { + int length = (_offset - _startOffset) - 3; + + _buffer[_startOffset] = (byte) BC_BINARY_CHUNK; + _buffer[_startOffset + 1] = (byte) (length >> 8); + _buffer[_startOffset + 2] = (byte) (length); + + Hessian2Output.this.flush(); + + _startOffset = _offset; + _offset += 3; + } + + _buffer[_offset++] = (byte) ch; + } + + @Override + public void write(byte []buffer, int offset, int length) + throws IOException + { + while (length > 0) { + int sublen = SIZE - _offset; + + if (length < sublen) + sublen = length; + + if (sublen > 0) { + System.arraycopy(buffer, offset, _buffer, _offset, sublen); + _offset += sublen; + } + + length -= sublen; + offset += sublen; + + if (SIZE <= _offset) { + int chunkLength = (_offset - _startOffset) - 3; + + _buffer[_startOffset] = (byte) BC_BINARY_CHUNK; + _buffer[_startOffset + 1] = (byte) (chunkLength >> 8); + _buffer[_startOffset + 2] = (byte) (chunkLength); + + Hessian2Output.this.flush(); + + _startOffset = _offset; + _offset += 3; + } + } + } + + @Override + public void close() + throws IOException + { + int startOffset = _startOffset; + _startOffset = -1; + + if (startOffset < 0) + return; + + int length = (_offset - startOffset) - 3; + + _buffer[startOffset] = (byte) 'B'; + _buffer[startOffset + 1] = (byte) (length >> 8); + _buffer[startOffset + 2] = (byte) (length); + + Hessian2Output.this.flush(); + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java new file mode 100644 index 0000000000..ac8e8e9d9f --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java @@ -0,0 +1,165 @@ +/* + * 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 "Burlap", "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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Output stream for Hessian 2 streaming requests. + */ +public class Hessian2StreamingInput +{ + private Hessian2Input _in; + + /** + * Creates a new Hessian input stream, initialized with an + * underlying input stream. + * + * @param is the underlying output stream. + */ + public Hessian2StreamingInput(InputStream is) + { + _in = new Hessian2Input(new StreamingInputStream(is)); + } + + /** + * Read the next object + */ + public Object readObject() + throws IOException + { + return _in.readStreamingObject(); + } + + /** + * Close the output. + */ + public void close() + throws IOException + { + _in.close(); + } + + static class StreamingInputStream extends InputStream { + private InputStream _is; + private int _length; + + StreamingInputStream(InputStream is) + { + _is = is; + } + + public int read() + throws IOException + { + InputStream is = _is; + + while (_length == 0) { + int code = is.read(); + + if (code < 0) + return -1; + else if (code != 'p' && code != 'P') + throw new HessianProtocolException("expected streaming packet at 0x" + + Integer.toHexString(code & 0xff)); + + int d1 = is.read(); + int d2 = is.read(); + + if (d2 < 0) + return -1; + + _length = (d1 << 8) + d2; + } + + _length--; + return is.read(); + } + + public int read(byte []buffer, int offset, int length) + throws IOException + { + InputStream is = _is; + + while (_length == 0) { + int code = is.read(); + + if (code < 0) + return -1; + else if (code != 'p' && code != 'P') { + throw new HessianProtocolException("expected streaming packet at 0x" + + Integer.toHexString(code & 0xff) + + " (" + (char) code + ")"); + } + + int d1 = is.read(); + int d2 = is.read(); + + if (d2 < 0) + return -1; + + _length = (d1 << 8) + d2; + } + + int sublen = _length; + if (length < sublen) + sublen = length; + + sublen = is.read(buffer, offset, sublen); + + if (sublen < 0) + return -1; + + _length -= sublen; + + return sublen; + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java new file mode 100644 index 0000000000..28c44cdf58 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java @@ -0,0 +1,109 @@ +/* + * 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 "Burlap", "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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; + +/** + * Output stream for Hessian 2 streaming requests. + */ +public class Hessian2StreamingOutput +{ + private Hessian2Output _out; + + /** + * Creates a new Hessian output stream, initialized with an + * underlying output stream. + * + * @param os the underlying output stream. + */ + public Hessian2StreamingOutput(OutputStream os) + { + _out = new Hessian2Output(os); + } + + public void setCloseStreamOnClose(boolean isClose) + { + _out.setCloseStreamOnClose(isClose); + } + + public boolean isCloseStreamOnClose() + { + return _out.isCloseStreamOnClose(); + } + + /** + * Writes any object to the output stream. + */ + public void writeObject(Object object) + throws IOException + { + _out.writeStreamingObject(object); + } + + /** + * Flushes the output. + */ + public void flush() + throws IOException + { + _out.flush(); + } + + /** + * Close the output. + */ + public void close() + throws IOException + { + _out.close(); + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugInputStream.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugInputStream.java new file mode 100644 index 0000000000..31e1f2881a --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugInputStream.java @@ -0,0 +1,174 @@ +/* + * 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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.io.PrintWriter; +import java.util.ArrayList; + +import java.util.logging.Logger; +import java.util.logging.Level; + +/** + * Debugging input stream for Hessian requests. + */ +public class HessianDebugInputStream extends InputStream +{ + private InputStream _is; + + private HessianDebugState _state; + + /** + * Creates an uninitialized Hessian input stream. + */ + public HessianDebugInputStream(InputStream is, PrintWriter dbg) + { + _is = is; + + if (dbg == null) + dbg = new PrintWriter(System.out); + + _state = new HessianDebugState(dbg); + } + + /** + * Creates an uninitialized Hessian input stream. + */ + public HessianDebugInputStream(InputStream is, Logger log, Level level) + { + this(is, new PrintWriter(new LogWriter(log, level))); + } + + public void startTop2() + { + _state.startTop2(); + } + + /** + * Reads a character. + */ + public int read() + throws IOException + { + int ch; + + InputStream is = _is; + + if (is == null) + return -1; + else { + ch = is.read(); + } + + _state.next(ch); + + return ch; + } + + /** + * closes the stream. + */ + public void close() + throws IOException + { + InputStream is = _is; + _is = null; + + if (is != null) + is.close(); + + _state.println(); + } + + static class LogWriter extends Writer { + private Logger _log; + private Level _level; + private StringBuilder _sb = new StringBuilder(); + + LogWriter(Logger log, Level level) + { + _log = log; + _level = level; + } + + public void write(char ch) + { + if (ch == '\n' && _sb.length() > 0) { + _log.log(_level, _sb.toString()); + _sb.setLength(0); + } + else + _sb.append((char) ch); + } + + public void write(char []buffer, int offset, int length) + { + for (int i = 0; i < length; i++) { + char ch = buffer[offset + i]; + + if (ch == '\n' && _sb.length() > 0) { + _log.log(_level, _sb.toString()); + _sb.setLength(0); + } + else + _sb.append((char) ch); + } + } + + public void flush() + { + } + + public void close() + { + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugOutputStream.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugOutputStream.java new file mode 100644 index 0000000000..0511e664f2 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugOutputStream.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.io.PrintWriter; + +import java.util.logging.Logger; +import java.util.logging.Level; + +/** + * Debugging output stream for Hessian requests. + */ +public class HessianDebugOutputStream extends OutputStream +{ + private OutputStream _os; + + private HessianDebugState _state; + + /** + * Creates an uninitialized Hessian input stream. + */ + public HessianDebugOutputStream(OutputStream os, PrintWriter dbg) + { + _os = os; + + _state = new HessianDebugState(dbg); + } + + /** + * Creates an uninitialized Hessian input stream. + */ + public HessianDebugOutputStream(OutputStream os, Logger log, Level level) + { + this(os, new PrintWriter(new LogWriter(log, level))); + } + + public void startTop2() + { + _state.startTop2(); + } + + /** + * Writes a character. + */ + public void write(int ch) + throws IOException + { + ch = ch & 0xff; + + _os.write(ch); + + _state.next(ch); + } + + public void flush() + throws IOException + { + _os.flush(); + } + + /** + * closes the stream. + */ + public void close() + throws IOException + { + OutputStream os = _os; + _os = null; + + if (os != null) + os.close(); + + _state.println(); + } + + static class LogWriter extends Writer { + private Logger _log; + private Level _level; + private StringBuilder _sb = new StringBuilder(); + + LogWriter(Logger log, Level level) + { + _log = log; + _level = level; + } + + public void write(char ch) + { + if (ch == '\n' && _sb.length() > 0) { + _log.log(_level, _sb.toString()); + _sb.setLength(0); + } + else + _sb.append((char) ch); + } + + public void write(char []buffer, int offset, int length) + { + for (int i = 0; i < length; i++) { + char ch = buffer[offset + i]; + + if (ch == '\n' && _sb.length() > 0) { + _log.log(_level, _sb.toString()); + _sb.setLength(0); + } + else + _sb.append((char) ch); + } + } + + public void flush() + { + } + + public void close() + { + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugState.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugState.java new file mode 100644 index 0000000000..89239e842f --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugState.java @@ -0,0 +1,2090 @@ +/* + * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * Debugging input stream for Hessian requests. + */ +public class HessianDebugState implements Hessian2Constants +{ + private PrintWriter _dbg; + + private State _state; + private ArrayList
HessianInput is unbuffered, so any client needs to provide + * its own buffering. + * + *
+ * InputStream is = ...; // from http connection + * HessianInput in = new HessianInput(is); + * String value; + * + * in.startReply(); // read reply header + * value = in.readString(); // read string value + * in.completeReply(); // read reply footer + *+ */ +public class HessianInput extends AbstractHessianInput { + private static int END_OF_DATA = -2; + + private static Field _detailMessageField; + + // factory for deserializing objects in the input stream + protected SerializerFactory _serializerFactory; + + protected ArrayList _refs; + + // the underlying input stream + private InputStream _is; + // a peek character + protected int _peek = -1; + + // the method for a call + private String _method; + + private Reader _chunkReader; + private InputStream _chunkInputStream; + + private Throwable _replyFault; + + private StringBuffer _sbuf = new StringBuffer(); + + // true if this is the last chunk + private boolean _isLastChunk; + // the chunk length + private int _chunkLength; + + /** + * Creates an uninitialized Hessian input stream. + */ + public HessianInput() + { + } + + /** + * Creates a new Hessian input stream, initialized with an + * underlying input stream. + * + * @param is the underlying input stream. + */ + public HessianInput(InputStream is) + { + init(is); + } + + /** + * Sets the serializer factory. + */ + public void setSerializerFactory(SerializerFactory factory) + { + _serializerFactory = factory; + } + + /** + * Gets the serializer factory. + */ + public SerializerFactory getSerializerFactory() + { + return _serializerFactory; + } + + /** + * Initialize the hessian stream with the underlying input stream. + */ + public void init(InputStream is) + { + _is = is; + _method = null; + _isLastChunk = true; + _chunkLength = 0; + _peek = -1; + _refs = null; + _replyFault = null; + + if (_serializerFactory == null) + _serializerFactory = new SerializerFactory(); + } + + /** + * Returns the calls method + */ + public String getMethod() + { + return _method; + } + + /** + * Returns any reply fault. + */ + public Throwable getReplyFault() + { + return _replyFault; + } + + /** + * Starts reading the call + * + *
+ * c major minor + *+ */ + public int readCall() + throws IOException + { + int tag = read(); + + if (tag != 'c') + throw error("expected hessian call ('c') at " + codeName(tag)); + + int major = read(); + int minor = read(); + + return (major << 16) + minor; + } + + /** + * For backward compatibility with HessianSkeleton + */ + public void skipOptionalCall() + throws IOException + { + int tag = read(); + + if (tag == 'c') { + read(); + read(); + } + else + _peek = tag; + } + + /** + * Starts reading the call + * + *
A successful completion will have a single value: + * + *
+ * m b16 b8 method + *+ */ + public String readMethod() + throws IOException + { + int tag = read(); + + if (tag != 'm') + throw error("expected hessian method ('m') at " + codeName(tag)); + int d1 = read(); + int d2 = read(); + + _isLastChunk = true; + _chunkLength = d1 * 256 + d2; + _sbuf.setLength(0); + int ch; + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + _method = _sbuf.toString(); + + return _method; + } + + /** + * Starts reading the call, including the headers. + * + *
The call expects the following protocol data + * + *
+ * c major minor + * m b16 b8 method + *+ */ + public void startCall() + throws IOException + { + readCall(); + + while (readHeader() != null) { + readObject(); + } + + readMethod(); + } + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeCall() + throws IOException + { + int tag = read(); + + if (tag == 'z') { + } + else + throw error("expected end of call ('z') at " + codeName(tag) + ". Check method arguments and ensure method overloading is enabled if necessary"); + } + + /** + * Reads a reply as an object. + * If the reply has a fault, throws the exception. + */ + public Object readReply(Class expectedClass) + throws Throwable + { + int tag = read(); + + if (tag != 'r') + error("expected hessian reply at " + codeName(tag)); + + int major = read(); + int minor = read(); + + tag = read(); + if (tag == 'f') + throw prepareFault(); + else { + _peek = tag; + + Object value = readObject(expectedClass); + + completeValueReply(); + + return value; + } + } + + /** + * Starts reading the reply + * + *
A successful completion will have a single value: + * + *
+ * r + *+ */ + public void startReply() + throws Throwable + { + int tag = read(); + + if (tag != 'r') + error("expected hessian reply at " + codeName(tag)); + + int major = read(); + int minor = read(); + + tag = read(); + if (tag == 'f') + throw prepareFault(); + else + _peek = tag; + } + + /** + * Prepares the fault. + */ + private Throwable prepareFault() + throws IOException + { + HashMap fault = readFault(); + + Object detail = fault.get("detail"); + String message = (String) fault.get("message"); + + if (detail instanceof Throwable) { + _replyFault = (Throwable) detail; + + if (message != null && _detailMessageField != null) { + try { + _detailMessageField.set(_replyFault, message); + } catch (Throwable e) { + } + } + + return _replyFault; + } + + else { + String code = (String) fault.get("code"); + + _replyFault = new HessianServiceException(message, code, detail); + + return _replyFault; + } + } + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeReply() + throws IOException + { + int tag = read(); + + if (tag != 'z') + error("expected end of reply at " + codeName(tag)); + } + + /** + * Completes reading the call + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeValueReply() + throws IOException + { + int tag = read(); + + if (tag != 'z') + error("expected end of reply at " + codeName(tag)); + } + + /** + * Reads a header, returning null if there are no headers. + * + *
+ * H b16 b8 value + *+ */ + public String readHeader() + throws IOException + { + int tag = read(); + + if (tag == 'H') { + _isLastChunk = true; + _chunkLength = (read() << 8) + read(); + + _sbuf.setLength(0); + int ch; + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + } + + _peek = tag; + + return null; + } + + /** + * Reads a null + * + *
+ * N + *+ */ + public void readNull() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': return; + + default: + throw expect("null", tag); + } + } + + /** + * Reads a boolean + * + *
+ * T + * F + *+ */ + public boolean readBoolean() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'T': return true; + case 'F': return false; + case 'I': return parseInt() == 0; + case 'L': return parseLong() == 0; + case 'D': return parseDouble() == 0.0; + case 'N': return false; + + default: + throw expect("boolean", tag); + } + } + + /** + * Reads a byte + * + *
+ * I b32 b24 b16 b8 + *+ */ + /* + public byte readByte() + throws IOException + { + return (byte) readInt(); + } + */ + + /** + * Reads a short + * + *
+ * I b32 b24 b16 b8 + *+ */ + public short readShort() + throws IOException + { + return (short) readInt(); + } + + /** + * Reads an integer + * + *
+ * I b32 b24 b16 b8 + *+ */ + public int readInt() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'T': return 1; + case 'F': return 0; + case 'I': return parseInt(); + case 'L': return (int) parseLong(); + case 'D': return (int) parseDouble(); + + default: + throw expect("int", tag); + } + } + + /** + * Reads a long + * + *
+ * L b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public long readLong() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'T': return 1; + case 'F': return 0; + case 'I': return parseInt(); + case 'L': return parseLong(); + case 'D': return (long) parseDouble(); + + default: + throw expect("long", tag); + } + } + + /** + * Reads a float + * + *
+ * D b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public float readFloat() + throws IOException + { + return (float) readDouble(); + } + + /** + * Reads a double + * + *
+ * D b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public double readDouble() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'T': return 1; + case 'F': return 0; + case 'I': return parseInt(); + case 'L': return (double) parseLong(); + case 'D': return parseDouble(); + + default: + throw expect("long", tag); + } + } + + /** + * Reads a date. + * + *
+ * T b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + public long readUTCDate() + throws IOException + { + int tag = read(); + + if (tag != 'd') + throw error("expected date at " + codeName(tag)); + + long b64 = read(); + long b56 = read(); + long b48 = read(); + long b40 = read(); + long b32 = read(); + long b24 = read(); + long b16 = read(); + long b8 = read(); + + return ((b64 << 56) + + (b56 << 48) + + (b48 << 40) + + (b40 << 32) + + (b32 << 24) + + (b24 << 16) + + (b16 << 8) + + b8); + } + + /** + * Reads a byte from the stream. + */ + public int readChar() + throws IOException + { + if (_chunkLength > 0) { + _chunkLength--; + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + int ch = parseUTF8Char(); + return ch; + } + else if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'S': + case 's': + case 'X': + case 'x': + _isLastChunk = tag == 'S' || tag == 'X'; + _chunkLength = (read() << 8) + read(); + + _chunkLength--; + int value = parseUTF8Char(); + + // special code so successive read byte won't + // be read as a single object. + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + return value; + + default: + throw new IOException("expected 'S' at " + (char) tag); + } + } + + /** + * Reads a byte array from the stream. + */ + public int readString(char []buffer, int offset, int length) + throws IOException + { + int readLength = 0; + + if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + else if (_chunkLength == 0) { + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'S': + case 's': + case 'X': + case 'x': + _isLastChunk = tag == 'S' || tag == 'X'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw new IOException("expected 'S' at " + (char) tag); + } + } + + while (length > 0) { + if (_chunkLength > 0) { + buffer[offset++] = (char) parseUTF8Char(); + _chunkLength--; + length--; + readLength++; + } + else if (_isLastChunk) { + if (readLength == 0) + return -1; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + else { + int tag = read(); + + switch (tag) { + case 'S': + case 's': + case 'X': + case 'x': + _isLastChunk = tag == 'S' || tag == 'X'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw new IOException("expected 'S' at " + (char) tag); + } + } + } + + if (readLength == 0) + return -1; + else if (_chunkLength > 0 || ! _isLastChunk) + return readLength; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + + /** + * Reads a string + * + *
+ * S b16 b8 string value + *+ */ + public String readString() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'I': + return String.valueOf(parseInt()); + case 'L': + return String.valueOf(parseLong()); + case 'D': + return String.valueOf(parseDouble()); + + case 'S': + case 's': + case 'X': + case 'x': + _isLastChunk = tag == 'S' || tag == 'X'; + _chunkLength = (read() << 8) + read(); + + _sbuf.setLength(0); + int ch; + + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + + default: + throw expect("string", tag); + } + } + + /** + * Reads an XML node. + * + *
+ * S b16 b8 string value + *+ */ + public org.w3c.dom.Node readNode() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'S': + case 's': + case 'X': + case 'x': + _isLastChunk = tag == 'S' || tag == 'X'; + _chunkLength = (read() << 8) + read(); + + throw error("Can't handle string in this context"); + + default: + throw expect("string", tag); + } + } + + /** + * Reads a byte array + * + *
+ * B b16 b8 data value + *+ */ + public byte []readBytes() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'B': + case 'b': + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + int data; + while ((data = parseByte()) >= 0) + bos.write(data); + + return bos.toByteArray(); + + default: + throw expect("bytes", tag); + } + } + + /** + * Reads a byte from the stream. + */ + public int readByte() + throws IOException + { + if (_chunkLength > 0) { + _chunkLength--; + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + return read(); + } + else if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'B': + case 'b': + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + + int value = parseByte(); + + // special code so successive read byte won't + // be read as a single object. + if (_chunkLength == 0 && _isLastChunk) + _chunkLength = END_OF_DATA; + + return value; + + default: + throw new IOException("expected 'B' at " + (char) tag); + } + } + + /** + * Reads a byte array from the stream. + */ + public int readBytes(byte []buffer, int offset, int length) + throws IOException + { + int readLength = 0; + + if (_chunkLength == END_OF_DATA) { + _chunkLength = 0; + return -1; + } + else if (_chunkLength == 0) { + int tag = read(); + + switch (tag) { + case 'N': + return -1; + + case 'B': + case 'b': + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw new IOException("expected 'B' at " + (char) tag); + } + } + + while (length > 0) { + if (_chunkLength > 0) { + buffer[offset++] = (byte) read(); + _chunkLength--; + length--; + readLength++; + } + else if (_isLastChunk) { + if (readLength == 0) + return -1; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + else { + int tag = read(); + + switch (tag) { + case 'B': + case 'b': + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw new IOException("expected 'B' at " + (char) tag); + } + } + } + + if (readLength == 0) + return -1; + else if (_chunkLength > 0 || ! _isLastChunk) + return readLength; + else { + _chunkLength = END_OF_DATA; + return readLength; + } + } + + /** + * Reads a fault. + */ + private HashMap readFault() + throws IOException + { + HashMap map = new HashMap(); + + int code = read(); + for (; code > 0 && code != 'z'; code = read()) { + _peek = code; + + Object key = readObject(); + Object value = readObject(); + + if (key != null && value != null) + map.put(key, value); + } + + if (code != 'z') + throw expect("fault", code); + + return map; + } + + /** + * Reads an object from the input stream with an expected type. + */ + public Object readObject(Class cl) + throws IOException + { + if (cl == null || cl == Object.class) + return readObject(); + + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'M': + { + String type = readType(); + + // hessian/3386 + if ("".equals(type)) { + Deserializer reader; + reader = _serializerFactory.getDeserializer(cl); + + return reader.readMap(this); + } + else { + Deserializer reader; + reader = _serializerFactory.getObjectDeserializer(type,cl); + + return reader.readMap(this); + } + } + + case 'V': + { + String type = readType(); + int length = readLength(); + + Deserializer reader; + reader = _serializerFactory.getObjectDeserializer(type); + + if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) + return reader.readList(this, length); + + reader = _serializerFactory.getDeserializer(cl); + + Object v = reader.readList(this, length); + + return v; + } + + case 'R': + { + int ref = parseInt(); + + return _refs.get(ref); + } + + case 'r': + { + String type = readType(); + String url = readString(); + + return resolveRemote(type, url); + } + } + + _peek = tag; + + // hessian/332i vs hessian/3406 + //return readObject(); + + Object value = _serializerFactory.getDeserializer(cl).readObject(this); + + return value; + } + + /** + * Reads an arbitrary object from the input stream when the type + * is unknown. + */ + public Object readObject() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'T': + return Boolean.valueOf(true); + + case 'F': + return Boolean.valueOf(false); + + case 'I': + return Integer.valueOf(parseInt()); + + case 'L': + return Long.valueOf(parseLong()); + + case 'D': + return Double.valueOf(parseDouble()); + + case 'd': + return new Date(parseLong()); + + case 'x': + case 'X': { + _isLastChunk = tag == 'X'; + _chunkLength = (read() << 8) + read(); + + return parseXML(); + } + + case 's': + case 'S': { + _isLastChunk = tag == 'S'; + _chunkLength = (read() << 8) + read(); + + int data; + _sbuf.setLength(0); + + while ((data = parseChar()) >= 0) + _sbuf.append((char) data); + + return _sbuf.toString(); + } + + case 'b': + case 'B': { + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + + int data; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + while ((data = parseByte()) >= 0) + bos.write(data); + + return bos.toByteArray(); + } + + case 'V': { + String type = readType(); + int length = readLength(); + + return _serializerFactory.readList(this, length, type); + } + + case 'M': { + String type = readType(); + + return _serializerFactory.readMap(this, type); + } + + case 'R': { + int ref = parseInt(); + + return _refs.get(ref); + } + + case 'r': { + String type = readType(); + String url = readString(); + + return resolveRemote(type, url); + } + + default: + throw error("unknown code for readObject at " + codeName(tag)); + } + } + + /** + * Reads a remote object. + */ + public Object readRemote() + throws IOException + { + String type = readType(); + String url = readString(); + + return resolveRemote(type, url); + } + + /** + * Reads a reference. + */ + public Object readRef() + throws IOException + { + return _refs.get(parseInt()); + } + + /** + * Reads the start of a list. + */ + public int readListStart() + throws IOException + { + return read(); + } + + /** + * Reads the start of a list. + */ + public int readMapStart() + throws IOException + { + return read(); + } + + /** + * Returns true if this is the end of a list or a map. + */ + public boolean isEnd() + throws IOException + { + int code = read(); + + _peek = code; + + return (code < 0 || code == 'z'); + } + + /** + * Reads the end byte. + */ + public void readEnd() + throws IOException + { + int code = read(); + + if (code != 'z') + throw error("unknown code at " + codeName(code)); + } + + /** + * Reads the end byte. + */ + public void readMapEnd() + throws IOException + { + int code = read(); + + if (code != 'z') + throw error("expected end of map ('z') at " + codeName(code)); + } + + /** + * Reads the end byte. + */ + public void readListEnd() + throws IOException + { + int code = read(); + + if (code != 'z') + throw error("expected end of list ('z') at " + codeName(code)); + } + + /** + * Adds a list/map reference. + */ + public int addRef(Object ref) + { + if (_refs == null) + _refs = new ArrayList(); + + _refs.add(ref); + + return _refs.size() - 1; + } + + /** + * Adds a list/map reference. + */ + public void setRef(int i, Object ref) + { + _refs.set(i, ref); + } + + /** + * Resets the references for streaming. + */ + public void resetReferences() + { + if (_refs != null) + _refs.clear(); + } + + /** + * Resolves a remote object. + */ + public Object resolveRemote(String type, String url) + throws IOException + { + HessianRemoteResolver resolver = getRemoteResolver(); + + if (resolver != null) + return resolver.lookup(type, url); + else + return new HessianRemote(type, url); + } + + /** + * Parses a type from the stream. + * + *
+ * t b16 b8 + *+ */ + public String readType() + throws IOException + { + int code = read(); + + if (code != 't') { + _peek = code; + return ""; + } + + _isLastChunk = true; + _chunkLength = (read() << 8) + read(); + + _sbuf.setLength(0); + int ch; + while ((ch = parseChar()) >= 0) + _sbuf.append((char) ch); + + return _sbuf.toString(); + } + + /** + * Parses the length for an array + * + *
+ * l b32 b24 b16 b8 + *+ */ + public int readLength() + throws IOException + { + int code = read(); + + if (code != 'l') { + _peek = code; + return -1; + } + + return parseInt(); + } + + /** + * Parses a 32-bit integer value from the stream. + * + *
+ * b32 b24 b16 b8 + *+ */ + private int parseInt() + throws IOException + { + int b32 = read(); + int b24 = read(); + int b16 = read(); + int b8 = read(); + + return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8; + } + + /** + * Parses a 64-bit long value from the stream. + * + *
+ * b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + private long parseLong() + throws IOException + { + long b64 = read(); + long b56 = read(); + long b48 = read(); + long b40 = read(); + long b32 = read(); + long b24 = read(); + long b16 = read(); + long b8 = read(); + + return ((b64 << 56) + + (b56 << 48) + + (b48 << 40) + + (b40 << 32) + + (b32 << 24) + + (b24 << 16) + + (b16 << 8) + + b8); + } + + /** + * Parses a 64-bit double value from the stream. + * + *
+ * b64 b56 b48 b40 b32 b24 b16 b8 + *+ */ + private double parseDouble() + throws IOException + { + long b64 = read(); + long b56 = read(); + long b48 = read(); + long b40 = read(); + long b32 = read(); + long b24 = read(); + long b16 = read(); + long b8 = read(); + + long bits = ((b64 << 56) + + (b56 << 48) + + (b48 << 40) + + (b40 << 32) + + (b32 << 24) + + (b24 << 16) + + (b16 << 8) + + b8); + + return Double.longBitsToDouble(bits); + } + + org.w3c.dom.Node parseXML() + throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Reads a character from the underlying stream. + */ + private int parseChar() + throws IOException + { + while (_chunkLength <= 0) { + if (_isLastChunk) + return -1; + + int code = read(); + + switch (code) { + case 's': + case 'x': + _isLastChunk = false; + + _chunkLength = (read() << 8) + read(); + break; + + case 'S': + case 'X': + _isLastChunk = true; + + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("string", code); + } + + } + + _chunkLength--; + + return parseUTF8Char(); + } + + /** + * Parses a single UTF8 character. + */ + private int parseUTF8Char() + throws IOException + { + int ch = read(); + + if (ch < 0x80) + return ch; + else if ((ch & 0xe0) == 0xc0) { + int ch1 = read(); + int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f); + + return v; + } + else if ((ch & 0xf0) == 0xe0) { + int ch1 = read(); + int ch2 = read(); + int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f); + + return v; + } + else + throw error("bad utf-8 encoding at " + codeName(ch)); + } + + /** + * Reads a byte from the underlying stream. + */ + private int parseByte() + throws IOException + { + while (_chunkLength <= 0) { + if (_isLastChunk) { + return -1; + } + + int code = read(); + + switch (code) { + case 'b': + _isLastChunk = false; + + _chunkLength = (read() << 8) + read(); + break; + + case 'B': + _isLastChunk = true; + + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("byte[]", code); + } + } + + _chunkLength--; + + return read(); + } + + /** + * Reads bytes based on an input stream. + */ + public InputStream readInputStream() + throws IOException + { + int tag = read(); + + switch (tag) { + case 'N': + return null; + + case 'B': + case 'b': + _isLastChunk = tag == 'B'; + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("inputStream", tag); + } + + return new InputStream() { + boolean _isClosed = false; + + public int read() + throws IOException + { + if (_isClosed || _is == null) + return -1; + + int ch = parseByte(); + if (ch < 0) + _isClosed = true; + + return ch; + } + + public int read(byte []buffer, int offset, int length) + throws IOException + { + if (_isClosed || _is == null) + return -1; + + int len = HessianInput.this.read(buffer, offset, length); + if (len < 0) + _isClosed = true; + + return len; + } + + public void close() + throws IOException + { + while (read() >= 0) { + } + + _isClosed = true; + } + }; + } + + /** + * Reads bytes from the underlying stream. + */ + int read(byte []buffer, int offset, int length) + throws IOException + { + int readLength = 0; + + while (length > 0) { + while (_chunkLength <= 0) { + if (_isLastChunk) + return readLength == 0 ? -1 : readLength; + + int code = read(); + + switch (code) { + case 'b': + _isLastChunk = false; + + _chunkLength = (read() << 8) + read(); + break; + + case 'B': + _isLastChunk = true; + + _chunkLength = (read() << 8) + read(); + break; + + default: + throw expect("byte[]", code); + } + } + + int sublen = _chunkLength; + if (length < sublen) + sublen = length; + + sublen = _is.read(buffer, offset, sublen); + offset += sublen; + readLength += sublen; + length -= sublen; + _chunkLength -= sublen; + } + + return readLength; + } + + final int read() + throws IOException + { + if (_peek >= 0) { + int value = _peek; + _peek = -1; + return value; + } + + int ch = _is.read(); + + return ch; + } + + public void close() + { + _is = null; + } + + public Reader getReader() + { + return null; + } + + protected IOException expect(String expect, int ch) + { + return error("expected " + expect + " at " + codeName(ch)); + } + + protected String codeName(int ch) + { + if (ch < 0) + return "end of file"; + else + return "0x" + Integer.toHexString(ch & 0xff) + " (" + (char) + ch + ")"; + } + + protected IOException error(String message) + { + if (_method != null) + return new HessianProtocolException(_method + ": " + message); + else + return new HessianProtocolException(message); + } + + static { + try { + _detailMessageField = Throwable.class.getDeclaredField("detailMessage"); + _detailMessageField.setAccessible(true); + } catch (Throwable e) { + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInputFactory.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInputFactory.java new file mode 100644 index 0000000000..d5a24d1fd1 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInputFactory.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io; + +import java.util.logging.*; +import java.io.*; + +public class HessianInputFactory +{ + public static final Logger log + = Logger.getLogger(HessianInputFactory.class.getName()); + + private SerializerFactory _serializerFactory; + + public void setSerializerFactory(SerializerFactory factory) + { + _serializerFactory = factory; + } + + public SerializerFactory getSerializerFactory() + { + return _serializerFactory; + } + + public AbstractHessianInput open(InputStream is) + throws IOException + { + int code = is.read(); + + int major = is.read(); + int minor = is.read(); + + switch (code) { + case 'c': + case 'C': + case 'r': + case 'R': + if (major >= 2) { + AbstractHessianInput in = new Hessian2Input(is); + in.setSerializerFactory(_serializerFactory); + return in; + } + else { + AbstractHessianInput in = new HessianInput(is); + in.setSerializerFactory(_serializerFactory); + return in; + } + + default: + throw new IOException((char) code + " is an unknown Hessian message code."); + } + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianOutput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianOutput.java new file mode 100644 index 0000000000..6807f3db0f --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianOutput.java @@ -0,0 +1,949 @@ +/* + * 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 "Burlap", "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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.IdentityHashMap; + +/** + * Output stream for Hessian requests, compatible with microedition + * Java. It only uses classes and types available in JDK. + * + *
Since HessianOutput does not depend on any classes other than + * in the JDK, it can be extracted independently into a smaller package. + * + *
HessianOutput is unbuffered, so any client needs to provide + * its own buffering. + * + *
+ * OutputStream os = ...; // from http connection
+ * HessianOutput out = new HessianOutput(os);
+ * String value;
+ *
+ * out.startCall("hello"); // start hello call
+ * out.writeString("arg1"); // write a string argument
+ * out.completeCall(); // complete the call
+ *
+ */
+public class HessianOutput extends AbstractHessianOutput {
+ // the output stream/
+ protected OutputStream os;
+ // map of references
+ private IdentityHashMap _refs;
+ private int _version = 1;
+
+ /**
+ * Creates a new Hessian output stream, initialized with an
+ * underlying output stream.
+ *
+ * @param os the underlying output stream.
+ */
+ public HessianOutput(OutputStream os)
+ {
+ init(os);
+ }
+
+ /**
+ * Creates an uninitialized Hessian output stream.
+ */
+ public HessianOutput()
+ {
+ }
+
+ /**
+ * Initializes the output
+ */
+ public void init(OutputStream os)
+ {
+ this.os = os;
+
+ _refs = null;
+
+ if (_serializerFactory == null)
+ _serializerFactory = new SerializerFactory();
+ }
+
+ /**
+ * Sets the client's version.
+ */
+ public void setVersion(int version)
+ {
+ _version = version;
+ }
+
+ /**
+ * Writes a complete method call.
+ */
+ public void call(String method, Object []args)
+ throws IOException
+ {
+ int length = args != null ? args.length : 0;
+
+ startCall(method, length);
+
+ for (int i = 0; i < length; i++)
+ writeObject(args[i]);
+
+ completeCall();
+ }
+
+ /**
+ * Starts the method call. Clients would use startCall
+ * instead of call if they wanted finer control over
+ * writing the arguments, or needed to write headers.
+ *
+ *
+ * c major minor
+ * m b16 b8 method-name
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startCall(String method, int length)
+ throws IOException
+ {
+ os.write('c');
+ os.write(_version);
+ os.write(0);
+
+ os.write('m');
+ int len = method.length();
+ os.write(len >> 8);
+ os.write(len);
+ printString(method, 0, len);
+ }
+
+ /**
+ * Writes the call tag. This would be followed by the
+ * headers and the method tag.
+ *
+ *
+ * c major minor
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startCall()
+ throws IOException
+ {
+ os.write('c');
+ os.write(0);
+ os.write(1);
+ }
+
+ /**
+ * Writes the method tag.
+ *
+ *
+ * m b16 b8 method-name
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void writeMethod(String method)
+ throws IOException
+ {
+ os.write('m');
+ int len = method.length();
+ os.write(len >> 8);
+ os.write(len);
+ printString(method, 0, len);
+ }
+
+ /**
+ * Completes.
+ *
+ *
+ * z
+ *
+ */
+ public void completeCall()
+ throws IOException
+ {
+ os.write('z');
+ }
+
+ /**
+ * Starts the reply
+ *
+ * A successful completion will have a single value: + * + *
+ * r + *+ */ + public void startReply() + throws IOException + { + os.write('r'); + os.write(1); + os.write(0); + } + + /** + * Completes reading the reply + * + *
A successful completion will have a single value: + * + *
+ * z + *+ */ + public void completeReply() + throws IOException + { + os.write('z'); + } + + /** + * Writes a header name. The header value must immediately follow. + * + *
+ * H b16 b8 foo value
+ *
+ */
+ public void writeHeader(String name)
+ throws IOException
+ {
+ int len = name.length();
+
+ os.write('H');
+ os.write(len >> 8);
+ os.write(len);
+
+ printString(name);
+ }
+
+ /**
+ * Writes a fault. The fault will be written
+ * as a descriptive string followed by an object:
+ *
+ *
+ * f
+ * <string>code
+ * <string>the fault code
+ *
+ * <string>message
+ * <string>the fault mesage
+ *
+ * <string>detail
+ * mt\x00\xnnjavax.ejb.FinderException
+ * ...
+ * z
+ * z
+ *
+ *
+ * @param code the fault code, a three digit
+ */
+ public void writeFault(String code, String message, Object detail)
+ throws IOException
+ {
+ os.write('f');
+ writeString("code");
+ writeString(code);
+
+ writeString("message");
+ writeString(message);
+
+ if (detail != null) {
+ writeString("detail");
+ writeObject(detail);
+ }
+ os.write('z');
+ }
+
+ /**
+ * Writes any object to the output stream.
+ */
+ public void writeObject(Object object)
+ throws IOException
+ {
+ if (object == null) {
+ writeNull();
+ return;
+ }
+
+ Serializer serializer;
+
+ serializer = _serializerFactory.getSerializer(object.getClass());
+
+ serializer.writeObject(object, this);
+ }
+
+ /**
+ * Writes the list header to the stream. List writers will call
+ * writeListBegin followed by the list contents and then
+ * call writeListEnd.
+ *
+ *
+ * V
+ * t b16 b8 type
+ * l b32 b24 b16 b8
+ *
+ */
+ public boolean writeListBegin(int length, String type)
+ throws IOException
+ {
+ os.write('V');
+
+ if (type != null) {
+ os.write('t');
+ printLenString(type);
+ }
+
+ if (length >= 0) {
+ os.write('l');
+ os.write(length >> 24);
+ os.write(length >> 16);
+ os.write(length >> 8);
+ os.write(length);
+ }
+
+ return true;
+ }
+
+ /**
+ * Writes the tail of the list to the stream.
+ */
+ public void writeListEnd()
+ throws IOException
+ {
+ os.write('z');
+ }
+
+ /**
+ * Writes the map header to the stream. Map writers will call
+ * writeMapBegin followed by the map contents and then
+ * call writeMapEnd.
+ *
+ *
+ * Mt b16 b8 ( )z
+ *
+ */
+ public void writeMapBegin(String type)
+ throws IOException
+ {
+ os.write('M');
+ os.write('t');
+ printLenString(type);
+ }
+
+ /**
+ * Writes the tail of the map to the stream.
+ */
+ public void writeMapEnd()
+ throws IOException
+ {
+ os.write('z');
+ }
+
+ /**
+ * Writes a remote object reference to the stream. The type is the
+ * type of the remote interface.
+ *
+ *
+ * 'r' 't' b16 b8 type url
+ *
+ */
+ public void writeRemote(String type, String url)
+ throws IOException
+ {
+ os.write('r');
+ os.write('t');
+ printLenString(type);
+ os.write('S');
+ printLenString(url);
+ }
+
+ /**
+ * Writes a boolean value to the stream. The boolean will be written
+ * with the following syntax:
+ *
+ *
+ * T
+ * F
+ *
+ *
+ * @param value the boolean value to write.
+ */
+ public void writeBoolean(boolean value)
+ throws IOException
+ {
+ if (value)
+ os.write('T');
+ else
+ os.write('F');
+ }
+
+ /**
+ * Writes an integer value to the stream. The integer will be written
+ * with the following syntax:
+ *
+ *
+ * I b32 b24 b16 b8
+ *
+ *
+ * @param value the integer value to write.
+ */
+ public void writeInt(int value)
+ throws IOException
+ {
+ os.write('I');
+ os.write(value >> 24);
+ os.write(value >> 16);
+ os.write(value >> 8);
+ os.write(value);
+ }
+
+ /**
+ * Writes a long value to the stream. The long will be written
+ * with the following syntax:
+ *
+ *
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param value the long value to write.
+ */
+ public void writeLong(long value)
+ throws IOException
+ {
+ os.write('L');
+ os.write((byte) (value >> 56));
+ os.write((byte) (value >> 48));
+ os.write((byte) (value >> 40));
+ os.write((byte) (value >> 32));
+ os.write((byte) (value >> 24));
+ os.write((byte) (value >> 16));
+ os.write((byte) (value >> 8));
+ os.write((byte) (value));
+ }
+
+ /**
+ * Writes a double value to the stream. The double will be written
+ * with the following syntax:
+ *
+ *
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param value the double value to write.
+ */
+ public void writeDouble(double value)
+ throws IOException
+ {
+ long bits = Double.doubleToLongBits(value);
+
+ os.write('D');
+ os.write((byte) (bits >> 56));
+ os.write((byte) (bits >> 48));
+ os.write((byte) (bits >> 40));
+ os.write((byte) (bits >> 32));
+ os.write((byte) (bits >> 24));
+ os.write((byte) (bits >> 16));
+ os.write((byte) (bits >> 8));
+ os.write((byte) (bits));
+ }
+
+ /**
+ * Writes a date to the stream.
+ *
+ *
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @param time the date in milliseconds from the epoch in UTC
+ */
+ public void writeUTCDate(long time)
+ throws IOException
+ {
+ os.write('d');
+ os.write((byte) (time >> 56));
+ os.write((byte) (time >> 48));
+ os.write((byte) (time >> 40));
+ os.write((byte) (time >> 32));
+ os.write((byte) (time >> 24));
+ os.write((byte) (time >> 16));
+ os.write((byte) (time >> 8));
+ os.write((byte) (time));
+ }
+
+ /**
+ * Writes a null value to the stream.
+ * The null will be written with the following syntax
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeNull()
+ throws IOException
+ {
+ os.write('N');
+ }
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeString(String value)
+ throws IOException
+ {
+ if (value == null) {
+ os.write('N');
+ }
+ else {
+ int length = value.length();
+ int offset = 0;
+
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ // chunk can't end in high surrogate
+ char tail = value.charAt(offset + sublen - 1);
+
+ if (0xd800 <= tail && tail <= 0xdbff)
+ sublen--;
+
+ os.write('s');
+ os.write(sublen >> 8);
+ os.write(sublen);
+
+ printString(value, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+
+ os.write('S');
+ os.write(length >> 8);
+ os.write(length);
+
+ printString(value, offset, length);
+ }
+ }
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeString(char []buffer, int offset, int length)
+ throws IOException
+ {
+ if (buffer == null) {
+ os.write('N');
+ }
+ else {
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ // chunk can't end in high surrogate
+ char tail = buffer[offset + sublen - 1];
+
+ if (0xd800 <= tail && tail <= 0xdbff)
+ sublen--;
+
+ os.write('s');
+ os.write(sublen >> 8);
+ os.write(sublen);
+
+ printString(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+
+ os.write('S');
+ os.write(length >> 8);
+ os.write(length);
+
+ printString(buffer, offset, length);
+ }
+ }
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeBytes(byte []buffer)
+ throws IOException
+ {
+ if (buffer == null)
+ os.write('N');
+ else
+ writeBytes(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * N
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeBytes(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ if (buffer == null) {
+ os.write('N');
+ }
+ else {
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ os.write('b');
+ os.write(sublen >> 8);
+ os.write(sublen);
+
+ os.write(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+
+ os.write('B');
+ os.write(length >> 8);
+ os.write(length);
+ os.write(buffer, offset, length);
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ *
+ */
+ public void writeByteBufferStart()
+ throws IOException
+ {
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ */
+ public void writeByteBufferPart(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ while (length > 0) {
+ int sublen = length;
+
+ if (0x8000 < sublen)
+ sublen = 0x8000;
+
+ os.write('b');
+ os.write(sublen >> 8);
+ os.write(sublen);
+
+ os.write(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ */
+ public void writeByteBufferEnd(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ writeBytes(buffer, offset, length);
+ }
+
+ /**
+ * Writes a reference.
+ *
+ *
+ * R b32 b24 b16 b8
+ *
+ *
+ * @param value the integer value to write.
+ */
+ public void writeRef(int value)
+ throws IOException
+ {
+ os.write('R');
+ os.write(value >> 24);
+ os.write(value >> 16);
+ os.write(value >> 8);
+ os.write(value);
+ }
+
+ /**
+ * Writes a placeholder.
+ *
+ *
+ * P
+ *
+ */
+ public void writePlaceholder()
+ throws IOException
+ {
+ os.write('P');
+ }
+
+ /**
+ * If the object has already been written, just write its ref.
+ *
+ * @return true if we're writing a ref.
+ */
+ public boolean addRef(Object object)
+ throws IOException
+ {
+ if (_refs == null)
+ _refs = new IdentityHashMap();
+
+ Integer ref = (Integer) _refs.get(object);
+
+ if (ref != null) {
+ int value = ref.intValue();
+
+ writeRef(value);
+ return true;
+ }
+ else {
+ _refs.put(object, new Integer(_refs.size()));
+
+ return false;
+ }
+ }
+
+ /**
+ * Resets the references for streaming.
+ */
+ public void resetReferences()
+ {
+ if (_refs != null)
+ _refs.clear();
+ }
+
+ /**
+ * Removes a reference.
+ */
+ public boolean removeRef(Object obj)
+ throws IOException
+ {
+ if (_refs != null) {
+ _refs.remove(obj);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Replaces a reference from one object to another.
+ */
+ public boolean replaceRef(Object oldRef, Object newRef)
+ throws IOException
+ {
+ Integer value = (Integer) _refs.remove(oldRef);
+
+ if (value != null) {
+ _refs.put(newRef, value);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8 with preceeding length
+ *
+ * @param v the string to print.
+ */
+ public void printLenString(String v)
+ throws IOException
+ {
+ if (v == null) {
+ os.write(0);
+ os.write(0);
+ }
+ else {
+ int len = v.length();
+ os.write(len >> 8);
+ os.write(len);
+
+ printString(v, 0, len);
+ }
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8
+ *
+ * @param v the string to print.
+ */
+ public void printString(String v)
+ throws IOException
+ {
+ printString(v, 0, v.length());
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8
+ *
+ * @param v the string to print.
+ */
+ public void printString(String v, int offset, int length)
+ throws IOException
+ {
+ for (int i = 0; i < length; i++) {
+ char ch = v.charAt(i + offset);
+
+ if (ch < 0x80)
+ os.write(ch);
+ else if (ch < 0x800) {
+ os.write(0xc0 + ((ch >> 6) & 0x1f));
+ os.write(0x80 + (ch & 0x3f));
+ }
+ else {
+ os.write(0xe0 + ((ch >> 12) & 0xf));
+ os.write(0x80 + ((ch >> 6) & 0x3f));
+ os.write(0x80 + (ch & 0x3f));
+ }
+ }
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8
+ *
+ * @param v the string to print.
+ */
+ public void printString(char []v, int offset, int length)
+ throws IOException
+ {
+ for (int i = 0; i < length; i++) {
+ char ch = v[i + offset];
+
+ if (ch < 0x80)
+ os.write(ch);
+ else if (ch < 0x800) {
+ os.write(0xc0 + ((ch >> 6) & 0x1f));
+ os.write(0x80 + (ch & 0x3f));
+ }
+ else {
+ os.write(0xe0 + ((ch >> 12) & 0xf));
+ os.write(0x80 + ((ch >> 6) & 0x3f));
+ os.write(0x80 + (ch & 0x3f));
+ }
+ }
+ }
+
+ public void flush()
+ throws IOException
+ {
+ if (this.os != null)
+ this.os.flush();
+ }
+
+ public void close()
+ throws IOException
+ {
+ if (this.os != null)
+ this.os.flush();
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java
new file mode 100644
index 0000000000..e3f023e3ed
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java
@@ -0,0 +1,110 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Exception for faults when the fault doesn't return a java exception.
+ * This exception is required for MicroHessianInput.
+ */
+public class HessianProtocolException extends IOException {
+ private Throwable rootCause;
+
+ /**
+ * Zero-arg constructor.
+ */
+ public HessianProtocolException()
+ {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianProtocolException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianProtocolException(String message, Throwable rootCause)
+ {
+ super(message);
+
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianProtocolException(Throwable rootCause)
+ {
+ super(String.valueOf(rootCause));
+
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Returns the underlying cause.
+ */
+ public Throwable getRootCause()
+ {
+ return rootCause;
+ }
+
+ /**
+ * Returns the underlying cause.
+ */
+ public Throwable getCause()
+ {
+ return getRootCause();
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java
new file mode 100644
index 0000000000..bef32aba93
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+/**
+ * Encapsulates a remote address when no stub is available, e.g. for
+ * Java MicroEdition.
+ */
+public class HessianRemote {
+ private String type;
+ private String url;
+
+ /**
+ * Creates a new Hessian remote object.
+ *
+ * @param type the remote stub interface
+ * @param url the remote url
+ */
+ public HessianRemote(String type, String url)
+ {
+ this.type = type;
+ this.url = url;
+ }
+
+ /**
+ * Creates an uninitialized Hessian remote.
+ */
+ public HessianRemote()
+ {
+ }
+
+ /**
+ * Returns the remote api class name.
+ */
+ public String getType()
+ {
+ return type;
+ }
+
+ /**
+ * Returns the remote URL.
+ */
+ public String getURL()
+ {
+ return url;
+ }
+
+ /**
+ * Sets the remote URL.
+ */
+ public void setURL(String url)
+ {
+ this.url = url;
+ }
+
+ /**
+ * Defines the hashcode.
+ */
+ public int hashCode()
+ {
+ return url.hashCode();
+ }
+
+ /**
+ * Defines equality
+ */
+ public boolean equals(Object obj)
+ {
+ if (! (obj instanceof HessianRemote))
+ return false;
+
+ HessianRemote remote = (HessianRemote) obj;
+
+ return url.equals(remote.url);
+ }
+
+ /**
+ * Readable version of the remote.
+ */
+ public String toString()
+ {
+ return "[HessianRemote " + url + "]";
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemoteObject.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemoteObject.java
new file mode 100644
index 0000000000..d33f47de32
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemoteObject.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+/**
+ * Interface for any hessian remote object.
+ */
+public interface HessianRemoteObject {
+ public String getHessianType();
+ public String getHessianURL();
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemoteResolver.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemoteResolver.java
new file mode 100644
index 0000000000..c14b0f1e1d
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemoteResolver.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Looks up remote objects. The default just returns a HessianRemote object.
+ */
+public interface HessianRemoteResolver {
+ /**
+ * Looks up a proxy object.
+ */
+ public Object lookup(String type, String url)
+ throws IOException;
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerInput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerInput.java
new file mode 100644
index 0000000000..9651f1353e
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerInput.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Input stream for Hessian requests, deserializing objects using the
+ * java.io.Serialization protocol.
+ *
+ * HessianSerializerInput is unbuffered, so any client needs to provide + * its own buffering. + * + *
+ * InputStream is = new FileInputStream("test.xml");
+ * HessianOutput in = new HessianSerializerOutput(is);
+ *
+ * Object obj = in.readObject();
+ * is.close();
+ *
+ *
+ * + * InputStream is = ...; // from http connection + * HessianInput in = new HessianSerializerInput(is); + * String value; + * + * in.startReply(); // read reply header + * value = in.readString(); // read string value + * in.completeReply(); // read reply footer + *+ */ +public class HessianSerializerInput extends HessianInput { + /** + * Creates a new Hessian input stream, initialized with an + * underlying input stream. + * + * @param is the underlying input stream. + */ + public HessianSerializerInput(InputStream is) + { + super(is); + } + + /** + * Creates an uninitialized Hessian input stream. + */ + public HessianSerializerInput() + { + } + + /** + * Reads an object from the input stream. cl is known not to be + * a Map. + */ + protected Object readObjectImpl(Class cl) + throws IOException + { + try { + Object obj = cl.newInstance(); + + if (_refs == null) + _refs = new ArrayList(); + _refs.add(obj); + + HashMap fieldMap = getFieldMap(cl); + + int code = read(); + for (; code >= 0 && code != 'z'; code = read()) { + _peek = code; + + Object key = readObject(); + + Field field = (Field) fieldMap.get(key); + + if (field != null) { + Object value = readObject(field.getType()); + field.set(obj, value); + } + else { + Object value = readObject(); + } + } + + if (code != 'z') + throw expect("map", code); + + // if there's a readResolve method, call it + try { + Method method = cl.getMethod("readResolve", new Class[0]); + return method.invoke(obj, new Object[0]); + } catch (Exception e) { + } + + return obj; + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOExceptionWrapper(e); + } + } + + /** + * Creates a map of the classes fields. + */ + protected HashMap getFieldMap(Class cl) + { + HashMap fieldMap = new HashMap(); + + for (; cl != null; cl = cl.getSuperclass()) { + Field []fields = cl.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + + if (Modifier.isTransient(field.getModifiers()) || + Modifier.isStatic(field.getModifiers())) + continue; + + // XXX: could parameterize the handler to only deal with public + field.setAccessible(true); + + fieldMap.put(field.getName(), field); + } + } + + return fieldMap; + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerOutput.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerOutput.java new file mode 100644 index 0000000000..5b570b33b5 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerOutput.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Output stream for Hessian requests. + * + *
HessianOutput is unbuffered, so any client needs to provide + * its own buffering. + * + *
+ * OutputStream os = new FileOutputStream("test.xml");
+ * HessianOutput out = new HessianSerializerOutput(os);
+ *
+ * out.writeObject(obj);
+ * os.close();
+ *
+ *
+ *
+ * OutputStream os = ...; // from http connection
+ * HessianOutput out = new HessianSerializerOutput(os);
+ * String value;
+ *
+ * out.startCall("hello"); // start hello call
+ * out.writeString("arg1"); // write a string argument
+ * out.completeCall(); // complete the call
+ *
+ */
+public class HessianSerializerOutput extends HessianOutput {
+ /**
+ * Creates a new Hessian output stream, initialized with an
+ * underlying output stream.
+ *
+ * @param os the underlying output stream.
+ */
+ public HessianSerializerOutput(OutputStream os)
+ {
+ super(os);
+ }
+
+ /**
+ * Creates an uninitialized Hessian output stream.
+ */
+ public HessianSerializerOutput()
+ {
+ }
+
+ /**
+ * Applications which override this can do custom serialization.
+ *
+ * @param object the object to write.
+ */
+ public void writeObjectImpl(Object obj)
+ throws IOException
+ {
+ Class cl = obj.getClass();
+
+ try {
+ Method method = cl.getMethod("writeReplace", new Class[0]);
+ Object repl = method.invoke(obj, new Object[0]);
+
+ writeObject(repl);
+ return;
+ } catch (Exception e) {
+ }
+
+ try {
+ writeMapBegin(cl.getName());
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field []fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers()) ||
+ Modifier.isStatic(field.getModifiers()))
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ field.setAccessible(true);
+
+ writeString(field.getName());
+ writeObject(field.get(obj));
+ }
+ }
+ writeMapEnd();
+ } catch (IllegalAccessException e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianServiceException.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianServiceException.java
new file mode 100644
index 0000000000..248e58f532
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/HessianServiceException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+/**
+ * Exception for faults when the fault doesn't return a java exception.
+ * This exception is required for MicroHessianInput.
+ */
+public class HessianServiceException extends Exception {
+ private String code;
+ private Object detail;
+
+ /**
+ * Zero-arg constructor.
+ */
+ public HessianServiceException()
+ {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianServiceException(String message, String code, Object detail)
+ {
+ super(message);
+ this.code = code;
+ this.detail = detail;
+ }
+
+ /**
+ * Returns the code.
+ */
+ public String getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Returns the detail.
+ */
+ public Object getDetail()
+ {
+ return detail;
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java
new file mode 100644
index 0000000000..bee3cf531e
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Exception wrapper for IO.
+ */
+public class IOExceptionWrapper extends IOException {
+ private Throwable _cause;
+
+ public IOExceptionWrapper(Throwable cause)
+ {
+ super(cause.toString());
+
+ _cause = cause;
+ }
+
+ public IOExceptionWrapper(String msg, Throwable cause)
+ {
+ super(msg);
+
+ _cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return _cause;
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java
new file mode 100644
index 0000000000..d424794550
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Serializing a stream object.
+ */
+public class InputStreamDeserializer extends AbstractDeserializer {
+ public InputStreamDeserializer()
+ {
+ }
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ return in.readInputStream();
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java
new file mode 100644
index 0000000000..9ac9d66cec
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Serializing a stream object.
+ */
+public class InputStreamSerializer extends AbstractSerializer {
+ public InputStreamSerializer()
+ {
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ InputStream is = (InputStream) obj;
+
+ if (is == null)
+ out.writeNull();
+ else {
+ byte []buf = new byte[1024];
+ int len;
+
+ while ((len = is.read(buf, 0, buf.length)) > 0) {
+ out.writeByteBufferPart(buf, 0, len);
+ }
+
+ out.writeByteBufferEnd(buf, 0, 0);
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java
new file mode 100644
index 0000000000..b3bff92379
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * Serializing a JDK 1.2 Iterator.
+ */
+public class IteratorSerializer extends AbstractSerializer {
+ private static IteratorSerializer _serializer;
+
+ public static IteratorSerializer create()
+ {
+ if (_serializer == null)
+ _serializer = new IteratorSerializer();
+
+ return _serializer;
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ Iterator iter = (Iterator) obj;
+
+ boolean hasEnd = out.writeListBegin(-1, null);
+
+ while (iter.hasNext()) {
+ Object value = iter.next();
+
+ out.writeObject(value);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
new file mode 100644
index 0000000000..bd217c4e2b
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
@@ -0,0 +1,679 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+import java.util.logging.*;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class JavaDeserializer extends AbstractMapDeserializer {
+ private static final Logger log
+ = Logger.getLogger(JavaDeserializer.class.getName());
+
+ private Class _type;
+ private HashMap _fieldMap;
+ private Method _readResolve;
+ private Constructor _constructor;
+ private Object []_constructorArgs;
+
+ public JavaDeserializer(Class cl)
+ {
+ _type = cl;
+ _fieldMap = getFieldMap(cl);
+
+ _readResolve = getReadResolve(cl);
+
+ if (_readResolve != null) {
+ _readResolve.setAccessible(true);
+ }
+
+ Constructor []constructors = cl.getDeclaredConstructors();
+ long bestCost = Long.MAX_VALUE;
+
+ for (int i = 0; i < constructors.length; i++) {
+ Class []param = constructors[i].getParameterTypes();
+ long cost = 0;
+
+ for (int j = 0; j < param.length; j++) {
+ cost = 4 * cost;
+
+ if (Object.class.equals(param[j]))
+ cost += 1;
+ else if (String.class.equals(param[j]))
+ cost += 2;
+ else if (int.class.equals(param[j]))
+ cost += 3;
+ else if (long.class.equals(param[j]))
+ cost += 4;
+ else if (param[j].isPrimitive())
+ cost += 5;
+ else
+ cost += 6;
+ }
+
+ if (cost < 0 || cost > (1 << 48))
+ cost = 1 << 48;
+
+ cost += (long) param.length << 48;
+
+ if (cost < bestCost) {
+ _constructor = constructors[i];
+ bestCost = cost;
+ }
+ }
+
+ if (_constructor != null) {
+ _constructor.setAccessible(true);
+ Class []params = _constructor.getParameterTypes();
+ _constructorArgs = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ _constructorArgs[i] = getParamArg(params[i]);
+ }
+ }
+ }
+
+ public Class getType()
+ {
+ return _type;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ try {
+ Object obj = instantiate();
+
+ return readMap(in, obj);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in, String []fieldNames)
+ throws IOException
+ {
+ try {
+ Object obj = instantiate();
+
+ return readObject(in, obj, fieldNames);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Returns the readResolve method
+ */
+ protected Method getReadResolve(Class cl)
+ {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method []methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("readResolve") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ public Object readMap(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ try {
+ int ref = in.addRef(obj);
+
+ while (! in.isEnd()) {
+ Object key = in.readObject();
+
+ FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(key);
+
+ if (deser != null)
+ deser.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object resolve = resolve(obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ Object obj,
+ String []fieldNames)
+ throws IOException
+ {
+ try {
+ int ref = in.addRef(obj);
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String name = fieldNames[i];
+
+ FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(name);
+
+ if (deser != null)
+ deser.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ Object resolve = resolve(obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
+ }
+ }
+
+ private Object resolve(Object obj)
+ throws Exception
+ {
+ // if there's a readResolve method, call it
+ try {
+ if (_readResolve != null)
+ return _readResolve.invoke(obj, new Object[0]);
+ } catch (InvocationTargetException e) {
+ if (e.getTargetException() != null)
+ throw e;
+ }
+
+ return obj;
+ }
+
+ protected Object instantiate()
+ throws Exception
+ {
+ try {
+ if (_constructor != null)
+ return _constructor.newInstance(_constructorArgs);
+ else
+ return _type.newInstance();
+ } catch (Exception e) {
+ throw new HessianProtocolException("'" + _type.getName() + "' could not be instantiated", e);
+ }
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected HashMap getFieldMap(Class cl)
+ {
+ HashMap fieldMap = new HashMap();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field []fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers()))
+ continue;
+ else if (fieldMap.get(field.getName()) != null)
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ field.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ Class type = field.getType();
+ FieldDeserializer deser;
+
+ if (String.class.equals(type))
+ deser = new StringFieldDeserializer(field);
+ else if (byte.class.equals(type)) {
+ deser = new ByteFieldDeserializer(field);
+ }
+ else if (short.class.equals(type)) {
+ deser = new ShortFieldDeserializer(field);
+ }
+ else if (int.class.equals(type)) {
+ deser = new IntFieldDeserializer(field);
+ }
+ else if (long.class.equals(type)) {
+ deser = new LongFieldDeserializer(field);
+ }
+ else if (float.class.equals(type)) {
+ deser = new FloatFieldDeserializer(field);
+ }
+ else if (double.class.equals(type)) {
+ deser = new DoubleFieldDeserializer(field);
+ }
+ else if (boolean.class.equals(type)) {
+ deser = new BooleanFieldDeserializer(field);
+ }
+ else if (java.sql.Date.class.equals(type)) {
+ deser = new SqlDateFieldDeserializer(field);
+ }
+ else if (java.sql.Timestamp.class.equals(type)) {
+ deser = new SqlTimestampFieldDeserializer(field);
+ }
+ else if (java.sql.Time.class.equals(type)) {
+ deser = new SqlTimeFieldDeserializer(field);
+ }
+ else {
+ deser = new ObjectFieldDeserializer(field);
+ }
+
+ fieldMap.put(field.getName(), deser);
+ }
+ }
+
+ return fieldMap;
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected static Object getParamArg(Class cl)
+ {
+ if (! cl.isPrimitive())
+ return null;
+ else if (boolean.class.equals(cl))
+ return Boolean.FALSE;
+ else if (byte.class.equals(cl))
+ return new Byte((byte) 0);
+ else if (short.class.equals(cl))
+ return new Short((short) 0);
+ else if (char.class.equals(cl))
+ return new Character((char) 0);
+ else if (int.class.equals(cl))
+ return Integer.valueOf(0);
+ else if (long.class.equals(cl))
+ return Long.valueOf(0);
+ else if (float.class.equals(cl))
+ return Float.valueOf(0);
+ else if (double.class.equals(cl))
+ return Double.valueOf(0);
+ else
+ throw new UnsupportedOperationException();
+ }
+
+ abstract static class FieldDeserializer {
+ abstract void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException;
+ }
+
+ static class ObjectFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ObjectFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ Object value = null;
+
+ try {
+ value = in.readObject(_field.getType());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class BooleanFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ BooleanFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ boolean value = false;
+
+ try {
+ value = in.readBoolean();
+
+ _field.setBoolean(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ByteFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ByteFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setByte(obj, (byte) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ShortFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ShortFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setShort(obj, (short) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class IntFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ IntFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setInt(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class LongFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ LongFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ long value = 0;
+
+ try {
+ value = in.readLong();
+
+ _field.setLong(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class FloatFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ FloatFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _field.setFloat(obj, (float) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class DoubleFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ DoubleFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _field.setDouble(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class StringFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ StringFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ String value = null;
+
+ try {
+ value = in.readString();
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlDateFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ SqlDateFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ java.sql.Date value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+ value = new java.sql.Date(date.getTime());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimestampFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ SqlTimestampFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ java.sql.Timestamp value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+ if (date != null) value = new java.sql.Timestamp(date.getTime());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimeFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ SqlTimeFieldDeserializer(Field field)
+ {
+ _field = field;
+ }
+
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException
+ {
+ java.sql.Time value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+ value = new java.sql.Time(date.getTime());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static void logDeserializeError(Field field, Object obj, Object value,
+ Throwable e)
+ throws IOException
+ {
+ String fieldName = (field.getDeclaringClass().getName()
+ + "." + field.getName());
+
+ if (e instanceof HessianFieldException)
+ throw (HessianFieldException) e;
+ else if (e instanceof IOException)
+ throw new HessianFieldException(fieldName + ": " + e.getMessage(), e);
+
+ if (value != null)
+ throw new HessianFieldException(fieldName + ": " + value.getClass().getName() + " (" + value + ")"
+ + " cannot be assigned to '" + field.getType().getName() + "'", e);
+ else
+ throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java
new file mode 100644
index 0000000000..0103358b2b
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java
@@ -0,0 +1,434 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class JavaSerializer extends AbstractSerializer
+{
+ private static final Logger log
+ = Logger.getLogger(JavaSerializer.class.getName());
+
+ private static Object []NULL_ARGS = new Object[0];
+
+ private Field []_fields;
+ private FieldSerializer []_fieldSerializers;
+
+ private Object _writeReplaceFactory;
+ private Method _writeReplace;
+
+ public JavaSerializer(Class cl, ClassLoader loader)
+ {
+ introspectWriteReplace(cl, loader);
+
+ if (_writeReplace != null)
+ _writeReplace.setAccessible(true);
+
+ ArrayList primitiveFields = new ArrayList();
+ ArrayList compoundFields = new ArrayList();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field []fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers()))
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ field.setAccessible(true);
+
+ if (field.getType().isPrimitive()
+ || (field.getType().getName().startsWith("java.lang.")
+ && ! field.getType().equals(Object.class)))
+ primitiveFields.add(field);
+ else
+ compoundFields.add(field);
+ }
+ }
+
+ ArrayList fields = new ArrayList();
+ fields.addAll(primitiveFields);
+ fields.addAll(compoundFields);
+
+ _fields = new Field[fields.size()];
+ fields.toArray(_fields);
+
+ _fieldSerializers = new FieldSerializer[_fields.length];
+
+ for (int i = 0; i < _fields.length; i++) {
+ _fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
+ }
+ }
+
+ private void introspectWriteReplace(Class cl, ClassLoader loader)
+ {
+ try {
+ String className = cl.getName() + "HessianSerializer";
+
+ Class serializerClass = Class.forName(className, false, loader);
+
+ Object serializerObject = serializerClass.newInstance();
+
+ Method writeReplace = getWriteReplace(serializerClass, cl);
+
+ if (writeReplace != null) {
+ _writeReplaceFactory = serializerObject;
+ _writeReplace = writeReplace;
+
+ return;
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (Exception e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ _writeReplace = getWriteReplace(cl);
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected static Method getWriteReplace(Class cl)
+ {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method []methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("writeReplace") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected Method getWriteReplace(Class cl, Class param)
+ {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ for (Method method : cl.getDeclaredMethods()) {
+ if (method.getName().equals("writeReplace")
+ && method.getParameterTypes().length == 1
+ && param.equals(method.getParameterTypes()[0]))
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ Class cl = obj.getClass();
+
+ try {
+ if (_writeReplace != null) {
+ Object repl;
+
+ if (_writeReplaceFactory != null)
+ repl = _writeReplace.invoke(_writeReplaceFactory, obj);
+ else
+ repl = _writeReplace.invoke(obj);
+
+ out.removeRef(obj);
+
+ out.writeObject(repl);
+
+ out.replaceRef(repl, obj);
+
+ return;
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ // log.log(Level.FINE, e.toString(), e);
+ throw new RuntimeException(e);
+ }
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ writeObject10(obj, out);
+ }
+ else {
+ if (ref == -1) {
+ writeDefinition20(out);
+ out.writeObjectBegin(cl.getName());
+ }
+
+ writeInstance(obj, out);
+ }
+ }
+
+ private void writeObject10(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ out.writeString(field.getName());
+
+ _fieldSerializers[i].serialize(out, obj, field);
+ }
+
+ out.writeMapEnd();
+ }
+
+ private void writeDefinition20(AbstractHessianOutput out)
+ throws IOException
+ {
+ out.writeClassFieldLength(_fields.length);
+
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ out.writeString(field.getName());
+ }
+ }
+
+ public void writeInstance(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ _fieldSerializers[i].serialize(out, obj, field);
+ }
+ }
+
+ private static FieldSerializer getFieldSerializer(Class type)
+ {
+ if (int.class.equals(type)
+ || byte.class.equals(type)
+ || short.class.equals(type)
+ || int.class.equals(type)) {
+ return IntFieldSerializer.SER;
+ }
+ else if (long.class.equals(type)) {
+ return LongFieldSerializer.SER;
+ }
+ else if (double.class.equals(type) ||
+ float.class.equals(type)) {
+ return DoubleFieldSerializer.SER;
+ }
+ else if (boolean.class.equals(type)) {
+ return BooleanFieldSerializer.SER;
+ }
+ else if (String.class.equals(type)) {
+ return StringFieldSerializer.SER;
+ }
+ else if (java.util.Date.class.equals(type)
+ || java.sql.Date.class.equals(type)
+ || java.sql.Timestamp.class.equals(type)
+ || java.sql.Time.class.equals(type)) {
+ return DateFieldSerializer.SER;
+ }
+ else
+ return FieldSerializer.SER;
+ }
+
+ static class FieldSerializer {
+ static final FieldSerializer SER = new FieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ Object value = null;
+
+ try {
+ value = field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ try {
+ out.writeObject(value);
+ } catch (RuntimeException e) {
+ throw new RuntimeException(e.getMessage() + "\n Java field: " + field,
+ e);
+ } catch (IOException e) {
+ throw new IOExceptionWrapper(e.getMessage() + "\n Java field: " + field,
+ e);
+ }
+ }
+ }
+
+ static class BooleanFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new BooleanFieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ boolean value = false;
+
+ try {
+ value = field.getBoolean(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeBoolean(value);
+ }
+ }
+
+ static class IntFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new IntFieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ int value = 0;
+
+ try {
+ value = field.getInt(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeInt(value);
+ }
+ }
+
+ static class LongFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new LongFieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ long value = 0;
+
+ try {
+ value = field.getLong(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeLong(value);
+ }
+ }
+
+ static class DoubleFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new DoubleFieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ double value = 0;
+
+ try {
+ value = field.getDouble(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeDouble(value);
+ }
+ }
+
+ static class StringFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new StringFieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ String value = null;
+
+ try {
+ value = (String) field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeString(value);
+ }
+ }
+
+ static class DateFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new DateFieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException
+ {
+ java.util.Date value = null;
+
+ try {
+ value = (java.util.Date) field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ if (value == null)
+ out.writeNull();
+ else
+ out.writeUTCDate(value.getTime());
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java
new file mode 100644
index 0000000000..21454cf6c8
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java
@@ -0,0 +1,119 @@
+/*
+ * 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.alibaba.com.caucho.hessian.io;
+
+import java.util.Locale;
+
+/**
+ * Handle for a locale object.
+ */
+public class LocaleHandle implements java.io.Serializable, HessianHandle {
+ private String value;
+
+ public LocaleHandle(String locale)
+ {
+ this.value = locale;
+ }
+
+ private Object readResolve()
+ {
+ String s = this.value;
+
+ if (s == null)
+ return null;
+
+ int len = s.length();
+ char ch = ' ';
+
+ int i = 0;
+ for (;
+ i < len && ('a' <= (ch = s.charAt(i)) && ch <= 'z'
+ || 'A' <= ch && ch <= 'Z'
+ || '0' <= ch && ch <= '9');
+ i++) {
+ }
+
+ String language = s.substring(0, i);
+ String country = null;
+ String var = null;
+
+ if (ch == '-' || ch == '_') {
+ int head = ++i;
+
+ for (;
+ i < len && ('a' <= (ch = s.charAt(i)) && ch <= 'z'
+ || 'A' <= ch && ch <= 'Z'
+ || '0' <= ch && ch <= '9');
+ i++) {
+ }
+
+ country = s.substring(head, i);
+ }
+
+ if (ch == '-' || ch == '_') {
+ int head = ++i;
+
+ for (;
+ i < len && ('a' <= (ch = s.charAt(i)) && ch <= 'z'
+ || 'A' <= ch && ch <= 'Z'
+ || '0' <= ch && ch <= '9');
+ i++) {
+ }
+
+ var = s.substring(head, i);
+ }
+
+ if (var != null)
+ return new Locale(language, country, var);
+ else if (country != null)
+ return new Locale(language, country);
+ else
+ return new Locale(language);
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java
new file mode 100644
index 0000000000..367c986671
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.Locale;
+
+/**
+ * Serializing a locale.
+ */
+public class LocaleSerializer extends AbstractSerializer {
+ private static LocaleSerializer SERIALIZER = new LocaleSerializer();
+
+ public static LocaleSerializer create()
+ {
+ return SERIALIZER;
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (obj == null)
+ out.writeNull();
+ else {
+ Locale locale = (Locale) obj;
+
+ out.writeObject(new LocaleHandle(locale.toString()));
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java
new file mode 100644
index 0000000000..5c51d9a707
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.*;
+import java.lang.reflect.*;
+
+/**
+ * Deserializing a JDK 1.2 Map.
+ */
+public class MapDeserializer extends AbstractMapDeserializer {
+ private Class _type;
+ private Constructor _ctor;
+
+ public MapDeserializer(Class type)
+ {
+ if (type == null)
+ type = HashMap.class;
+
+ _type = type;
+
+ Constructor []ctors = type.getConstructors();
+ for (int i = 0; i < ctors.length; i++) {
+ if (ctors[i].getParameterTypes().length == 0)
+ _ctor = ctors[i];
+ }
+
+ if (_ctor == null) {
+ try {
+ _ctor = HashMap.class.getConstructor(new Class[0]);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ public Class getType()
+ {
+ if (_type != null)
+ return _type;
+ else
+ return HashMap.class;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ Map map;
+
+ if (_type == null)
+ map = new HashMap();
+ else if (_type.equals(Map.class))
+ map = new HashMap();
+ else if (_type.equals(SortedMap.class))
+ map = new TreeMap();
+ else {
+ try {
+ map = (Map) _ctor.newInstance();
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ in.addRef(map);
+
+ while (! in.isEnd()) {
+ map.put(in.readObject(), in.readObject());
+ }
+
+ in.readEnd();
+
+ return map;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ String []fieldNames)
+ throws IOException
+ {
+ Map map = createMap();
+
+ int ref = in.addRef(map);
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String name = fieldNames[i];
+
+ map.put(name, in.readObject());
+ }
+
+ return map;
+ }
+
+ private Map createMap()
+ throws IOException
+ {
+
+ if (_type == null)
+ return new HashMap();
+ else if (_type.equals(Map.class))
+ return new HashMap();
+ else if (_type.equals(SortedMap.class))
+ return new TreeMap();
+ else {
+ try {
+ return (Map) _ctor.newInstance();
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java
new file mode 100644
index 0000000000..c166060ab2
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Serializing a JDK 1.2 java.util.Map.
+ */
+public class MapSerializer extends AbstractSerializer {
+ private boolean _isSendJavaType = true;
+
+ /**
+ * Set true if the java type of the collection should be sent.
+ */
+ public void setSendJavaType(boolean sendJavaType)
+ {
+ _isSendJavaType = sendJavaType;
+ }
+
+ /**
+ * Return true if the java type of the collection should be sent.
+ */
+ public boolean getSendJavaType()
+ {
+ return _isSendJavaType;
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (out.addRef(obj))
+ return;
+
+ Map map = (Map) obj;
+
+ Class cl = obj.getClass();
+
+ if (cl.equals(HashMap.class)
+ || ! _isSendJavaType
+ || ! (obj instanceof java.io.Serializable))
+ out.writeMapBegin(null);
+ else
+ out.writeMapBegin(obj.getClass().getName());
+
+ Iterator iter = map.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Map.Entry) iter.next();
+
+ out.writeObject(entry.getKey());
+ out.writeObject(entry.getValue());
+ }
+ out.writeMapEnd();
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java
new file mode 100644
index 0000000000..5f554d1a54
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java
@@ -0,0 +1,100 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class ObjectDeserializer extends AbstractDeserializer {
+ private Class _cl;
+
+ public ObjectDeserializer(Class cl)
+ {
+ _cl = cl;
+ }
+
+ public Class getType()
+ {
+ return _cl;
+ }
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ return in.readObject();
+ }
+
+ public Object readObject(AbstractHessianInput in, String []fieldNames)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getSimpleName() + "[" + _cl + "]";
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java
new file mode 100644
index 0000000000..3d7e0d88d6
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Serializing a remote object.
+ */
+public class RemoteSerializer extends AbstractSerializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ // XXX: needs to be handled as a separate class
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Serializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Serializer.java
new file mode 100644
index 0000000000..67060d9a8f
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Serializer.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Serializing an object.
+ */
+public interface Serializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException;
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
new file mode 100644
index 0000000000..46a16fbceb
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
@@ -0,0 +1,649 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.*;
+
+/**
+ * Factory for returning serialization methods.
+ */
+public class SerializerFactory extends AbstractSerializerFactory
+{
+ private static final Logger log
+ = Logger.getLogger(SerializerFactory.class.getName());
+
+ private static Deserializer OBJECT_DESERIALIZER
+ = new BasicDeserializer(BasicDeserializer.OBJECT);
+
+ private static HashMap _staticSerializerMap;
+ private static HashMap _staticDeserializerMap;
+ private static HashMap _staticTypeMap;
+
+ private ClassLoader _loader;
+
+ protected Serializer _defaultSerializer;
+
+ // Additional factories
+ protected ArrayList _factories = new ArrayList();
+
+ protected CollectionSerializer _collectionSerializer;
+ protected MapSerializer _mapSerializer;
+
+ private Deserializer _hashMapDeserializer;
+ private Deserializer _arrayListDeserializer;
+ private HashMap _cachedSerializerMap;
+ private HashMap _cachedDeserializerMap;
+ private HashMap _cachedTypeDeserializerMap;
+
+ private boolean _isAllowNonSerializable;
+
+ public SerializerFactory()
+ {
+ this(Thread.currentThread().getContextClassLoader());
+ }
+
+ public SerializerFactory(ClassLoader loader)
+ {
+ _loader = loader;
+ }
+
+ public ClassLoader getClassLoader()
+ {
+ return _loader;
+ }
+
+ /**
+ * Set true if the collection serializer should send the java type.
+ */
+ public void setSendCollectionType(boolean isSendType)
+ {
+ if (_collectionSerializer == null)
+ _collectionSerializer = new CollectionSerializer();
+
+ _collectionSerializer.setSendJavaType(isSendType);
+
+ if (_mapSerializer == null)
+ _mapSerializer = new MapSerializer();
+
+ _mapSerializer.setSendJavaType(isSendType);
+ }
+
+ /**
+ * Adds a factory.
+ */
+ public void addFactory(AbstractSerializerFactory factory)
+ {
+ _factories.add(factory);
+ }
+
+ /**
+ * If true, non-serializable objects are allowed.
+ */
+ public void setAllowNonSerializable(boolean allow)
+ {
+ _isAllowNonSerializable = allow;
+ }
+
+ /**
+ * If true, non-serializable objects are allowed.
+ */
+ public boolean isAllowNonSerializable()
+ {
+ return _isAllowNonSerializable;
+ }
+
+ /**
+ * Returns the serializer for a class.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ *
+ * @return a serializer object for the serialization.
+ */
+ public Serializer getSerializer(Class cl)
+ throws HessianProtocolException
+ {
+ Serializer serializer;
+
+ serializer = (Serializer) _staticSerializerMap.get(cl);
+ if (serializer != null)
+ return serializer;
+
+ if (_cachedSerializerMap != null) {
+ synchronized (_cachedSerializerMap) {
+ serializer = (Serializer) _cachedSerializerMap.get(cl);
+ }
+
+ if (serializer != null)
+ return serializer;
+ }
+
+ for (int i = 0;
+ serializer == null && _factories != null && i < _factories.size();
+ i++) {
+ AbstractSerializerFactory factory;
+
+ factory = (AbstractSerializerFactory) _factories.get(i);
+
+ serializer = factory.getSerializer(cl);
+ }
+
+ if (serializer != null) {
+ }
+
+ else if (JavaSerializer.getWriteReplace(cl) != null)
+ serializer = new JavaSerializer(cl, _loader);
+
+ else if (HessianRemoteObject.class.isAssignableFrom(cl))
+ serializer = new RemoteSerializer();
+
+// else if (BurlapRemoteObject.class.isAssignableFrom(cl))
+// serializer = new RemoteSerializer();
+
+ else if (Map.class.isAssignableFrom(cl)) {
+ if (_mapSerializer == null)
+ _mapSerializer = new MapSerializer();
+
+ serializer = _mapSerializer;
+ }
+ else if (Collection.class.isAssignableFrom(cl)) {
+ if (_collectionSerializer == null) {
+ _collectionSerializer = new CollectionSerializer();
+ }
+
+ serializer = _collectionSerializer;
+ }
+
+ else if (cl.isArray())
+ serializer = new ArraySerializer();
+
+ else if (Throwable.class.isAssignableFrom(cl))
+ serializer = new ThrowableSerializer(cl, getClassLoader());
+
+ else if (InputStream.class.isAssignableFrom(cl))
+ serializer = new InputStreamSerializer();
+
+ else if (Iterator.class.isAssignableFrom(cl))
+ serializer = IteratorSerializer.create();
+
+ else if (Enumeration.class.isAssignableFrom(cl))
+ serializer = EnumerationSerializer.create();
+
+ else if (Calendar.class.isAssignableFrom(cl))
+ serializer = CalendarSerializer.create();
+
+ else if (Locale.class.isAssignableFrom(cl))
+ serializer = LocaleSerializer.create();
+
+ else if (Enum.class.isAssignableFrom(cl))
+ serializer = new EnumSerializer(cl);
+
+ if (serializer == null)
+ serializer = getDefaultSerializer(cl);
+
+ if (_cachedSerializerMap == null)
+ _cachedSerializerMap = new HashMap(8);
+
+ synchronized (_cachedSerializerMap) {
+ _cachedSerializerMap.put(cl, serializer);
+ }
+
+ return serializer;
+ }
+
+ /**
+ * Returns the default serializer for a class that isn't matched
+ * directly. Application can override this method to produce
+ * bean-style serialization instead of field serialization.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ *
+ * @return a serializer object for the serialization.
+ */
+ protected Serializer getDefaultSerializer(Class cl)
+ {
+ if (_defaultSerializer != null)
+ return _defaultSerializer;
+
+ if (! Serializable.class.isAssignableFrom(cl)
+ && ! _isAllowNonSerializable) {
+ throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");
+ }
+
+ return new JavaSerializer(cl, _loader);
+ }
+
+ /**
+ * Returns the deserializer for a class.
+ *
+ * @param cl the class of the object that needs to be deserialized.
+ *
+ * @return a deserializer object for the serialization.
+ */
+ public Deserializer getDeserializer(Class cl)
+ throws HessianProtocolException
+ {
+ Deserializer deserializer;
+
+ deserializer = (Deserializer) _staticDeserializerMap.get(cl);
+ if (deserializer != null)
+ return deserializer;
+
+ if (_cachedDeserializerMap != null) {
+ synchronized (_cachedDeserializerMap) {
+ deserializer = (Deserializer) _cachedDeserializerMap.get(cl);
+ }
+
+ if (deserializer != null)
+ return deserializer;
+ }
+
+
+ for (int i = 0;
+ deserializer == null && _factories != null && i < _factories.size();
+ i++) {
+ AbstractSerializerFactory factory;
+ factory = (AbstractSerializerFactory) _factories.get(i);
+
+ deserializer = factory.getDeserializer(cl);
+ }
+
+ if (deserializer != null) {
+ }
+
+ else if (Collection.class.isAssignableFrom(cl))
+ deserializer = new CollectionDeserializer(cl);
+
+ else if (Map.class.isAssignableFrom(cl))
+ deserializer = new MapDeserializer(cl);
+
+ else if (cl.isInterface())
+ deserializer = new ObjectDeserializer(cl);
+
+ else if (cl.isArray())
+ deserializer = new ArrayDeserializer(cl.getComponentType());
+
+ else if (Enumeration.class.isAssignableFrom(cl))
+ deserializer = EnumerationDeserializer.create();
+
+ else if (Enum.class.isAssignableFrom(cl))
+ deserializer = new EnumDeserializer(cl);
+
+ else if (Class.class.equals(cl))
+ deserializer = new ClassDeserializer(_loader);
+
+ else
+ deserializer = getDefaultDeserializer(cl);
+
+ if (_cachedDeserializerMap == null)
+ _cachedDeserializerMap = new HashMap(8);
+
+ synchronized (_cachedDeserializerMap) {
+ _cachedDeserializerMap.put(cl, deserializer);
+ }
+
+ return deserializer;
+ }
+
+ /**
+ * Returns the default serializer for a class that isn't matched
+ * directly. Application can override this method to produce
+ * bean-style serialization instead of field serialization.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ *
+ * @return a serializer object for the serialization.
+ */
+ protected Deserializer getDefaultDeserializer(Class cl)
+ {
+ return new JavaDeserializer(cl);
+ }
+
+ /**
+ * Reads the object as a list.
+ */
+ public Object readList(AbstractHessianInput in, int length, String type)
+ throws HessianProtocolException, IOException
+ {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer.readList(in, length);
+ else
+ return new CollectionDeserializer(ArrayList.class).readList(in, length);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Object readMap(AbstractHessianInput in, String type)
+ throws HessianProtocolException, IOException
+ {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer.readMap(in);
+ else if (_hashMapDeserializer != null)
+ return _hashMapDeserializer.readMap(in);
+ else {
+ _hashMapDeserializer = new MapDeserializer(HashMap.class);
+
+ return _hashMapDeserializer.readMap(in);
+ }
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Object readObject(AbstractHessianInput in,
+ String type,
+ String []fieldNames)
+ throws HessianProtocolException, IOException
+ {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer.readObject(in, fieldNames);
+ else if (_hashMapDeserializer != null)
+ return _hashMapDeserializer.readObject(in, fieldNames);
+ else {
+ _hashMapDeserializer = new MapDeserializer(HashMap.class);
+
+ return _hashMapDeserializer.readObject(in, fieldNames);
+ }
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getObjectDeserializer(String type, Class cl)
+ throws HessianProtocolException
+ {
+ Deserializer reader = getObjectDeserializer(type);
+
+ if (cl == null
+ || cl.equals(reader.getType())
+ || cl.isAssignableFrom(reader.getType())
+ || HessianHandle.class.isAssignableFrom(reader.getType())) {
+ return reader;
+ }
+
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("hessian: expected '" + cl.getName() + "' at '" + type + "' ("
+ + reader.getType().getName() + ")");
+ }
+
+ return getDeserializer(cl);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getObjectDeserializer(String type)
+ throws HessianProtocolException
+ {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer;
+ else if (_hashMapDeserializer != null)
+ return _hashMapDeserializer;
+ else {
+ _hashMapDeserializer = new MapDeserializer(HashMap.class);
+
+ return _hashMapDeserializer;
+ }
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getListDeserializer(String type, Class cl)
+ throws HessianProtocolException
+ {
+ Deserializer reader = getListDeserializer(type);
+
+ if (cl == null
+ || cl.equals(reader.getType())
+ || cl.isAssignableFrom(reader.getType())) {
+ return reader;
+ }
+
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("hessian: expected '" + cl.getName() + "' at '" + type + "' ("
+ + reader.getType().getName() + ")");
+ }
+
+ return getDeserializer(cl);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getListDeserializer(String type)
+ throws HessianProtocolException
+ {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer;
+ else if (_arrayListDeserializer != null)
+ return _arrayListDeserializer;
+ else {
+ _arrayListDeserializer = new CollectionDeserializer(ArrayList.class);
+
+ return _arrayListDeserializer;
+ }
+ }
+
+ /**
+ * Returns a deserializer based on a string type.
+ */
+ public Deserializer getDeserializer(String type)
+ throws HessianProtocolException
+ {
+ if (type == null || type.equals(""))
+ return null;
+
+ Deserializer deserializer;
+
+ if (_cachedTypeDeserializerMap != null) {
+ synchronized (_cachedTypeDeserializerMap) {
+ deserializer = (Deserializer) _cachedTypeDeserializerMap.get(type);
+ }
+
+ if (deserializer != null)
+ return deserializer;
+ }
+
+
+ deserializer = (Deserializer) _staticTypeMap.get(type);
+ if (deserializer != null)
+ return deserializer;
+
+ if (type.startsWith("[")) {
+ Deserializer subDeserializer = getDeserializer(type.substring(1));
+
+ if (subDeserializer != null)
+ deserializer = new ArrayDeserializer(subDeserializer.getType());
+ else
+ deserializer = new ArrayDeserializer(Object.class);
+ }
+ else {
+ try {
+ Class cl = Class.forName(type, false, _loader);
+ deserializer = getDeserializer(cl);
+ } catch (Exception e) {
+ log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
+
+ log.log(Level.FINER, e.toString(), e);
+ }
+ }
+
+ if (deserializer != null) {
+ if (_cachedTypeDeserializerMap == null)
+ _cachedTypeDeserializerMap = new HashMap(8);
+
+ synchronized (_cachedTypeDeserializerMap) {
+ _cachedTypeDeserializerMap.put(type, deserializer);
+ }
+ }
+
+ return deserializer;
+ }
+
+ private static void addBasic(Class cl, String typeName, int type)
+ {
+ _staticSerializerMap.put(cl, new BasicSerializer(type));
+
+ Deserializer deserializer = new BasicDeserializer(type);
+ _staticDeserializerMap.put(cl, deserializer);
+ _staticTypeMap.put(typeName, deserializer);
+ }
+
+ static {
+ _staticSerializerMap = new HashMap();
+ _staticDeserializerMap = new HashMap();
+ _staticTypeMap = new HashMap();
+
+ addBasic(void.class, "void", BasicSerializer.NULL);
+
+ addBasic(Boolean.class, "boolean", BasicSerializer.BOOLEAN);
+ addBasic(Byte.class, "byte", BasicSerializer.BYTE);
+ addBasic(Short.class, "short", BasicSerializer.SHORT);
+ addBasic(Integer.class, "int", BasicSerializer.INTEGER);
+ addBasic(Long.class, "long", BasicSerializer.LONG);
+ addBasic(Float.class, "float", BasicSerializer.FLOAT);
+ addBasic(Double.class, "double", BasicSerializer.DOUBLE);
+ addBasic(Character.class, "char", BasicSerializer.CHARACTER_OBJECT);
+ addBasic(String.class, "string", BasicSerializer.STRING);
+ addBasic(Object.class, "object", BasicSerializer.OBJECT);
+ addBasic(java.util.Date.class, "date", BasicSerializer.DATE);
+
+ addBasic(boolean.class, "boolean", BasicSerializer.BOOLEAN);
+ addBasic(byte.class, "byte", BasicSerializer.BYTE);
+ addBasic(short.class, "short", BasicSerializer.SHORT);
+ addBasic(int.class, "int", BasicSerializer.INTEGER);
+ addBasic(long.class, "long", BasicSerializer.LONG);
+ addBasic(float.class, "float", BasicSerializer.FLOAT);
+ addBasic(double.class, "double", BasicSerializer.DOUBLE);
+ addBasic(char.class, "char", BasicSerializer.CHARACTER);
+
+ addBasic(boolean[].class, "[boolean", BasicSerializer.BOOLEAN_ARRAY);
+ addBasic(byte[].class, "[byte", BasicSerializer.BYTE_ARRAY);
+ addBasic(short[].class, "[short", BasicSerializer.SHORT_ARRAY);
+ addBasic(int[].class, "[int", BasicSerializer.INTEGER_ARRAY);
+ addBasic(long[].class, "[long", BasicSerializer.LONG_ARRAY);
+ addBasic(float[].class, "[float", BasicSerializer.FLOAT_ARRAY);
+ addBasic(double[].class, "[double", BasicSerializer.DOUBLE_ARRAY);
+ addBasic(char[].class, "[char", BasicSerializer.CHARACTER_ARRAY);
+ addBasic(String[].class, "[string", BasicSerializer.STRING_ARRAY);
+ addBasic(Object[].class, "[object", BasicSerializer.OBJECT_ARRAY);
+
+ _staticSerializerMap.put(Class.class, new ClassSerializer());
+
+ _staticDeserializerMap.put(Number.class, new BasicDeserializer(BasicSerializer.NUMBER));
+
+ _staticSerializerMap.put(BigDecimal.class, new StringValueSerializer());
+ try {
+ _staticDeserializerMap.put(BigDecimal.class,
+ new StringValueDeserializer(BigDecimal.class));
+ _staticDeserializerMap.put(BigInteger.class,
+ new BigIntegerDeserializer());
+ } catch (Throwable e) {
+ }
+
+ _staticSerializerMap.put(File.class, new StringValueSerializer());
+ try {
+ _staticDeserializerMap.put(File.class,
+ new StringValueDeserializer(File.class));
+ } catch (Throwable e) {
+ }
+
+ _staticSerializerMap.put(ObjectName.class, new StringValueSerializer());
+ try {
+ _staticDeserializerMap.put(ObjectName.class,
+ new StringValueDeserializer(ObjectName.class));
+ } catch (Throwable e) {
+ }
+
+ _staticSerializerMap.put(java.sql.Date.class, new SqlDateSerializer());
+ _staticSerializerMap.put(java.sql.Time.class, new SqlDateSerializer());
+ _staticSerializerMap.put(java.sql.Timestamp.class, new SqlDateSerializer());
+
+ _staticSerializerMap.put(java.io.InputStream.class,
+ new InputStreamSerializer());
+ _staticDeserializerMap.put(java.io.InputStream.class,
+ new InputStreamDeserializer());
+
+ try {
+ _staticDeserializerMap.put(java.sql.Date.class,
+ new SqlDateDeserializer(java.sql.Date.class));
+ _staticDeserializerMap.put(java.sql.Time.class,
+ new SqlDateDeserializer(java.sql.Time.class));
+ _staticDeserializerMap.put(java.sql.Timestamp.class,
+ new SqlDateDeserializer(java.sql.Timestamp.class));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ // hessian/3bb5
+ try {
+ Class stackTrace = StackTraceElement.class;
+
+ _staticDeserializerMap.put(stackTrace, new StackTraceElementDeserializer());
+ } catch (Throwable e) {
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java
new file mode 100644
index 0000000000..b23c7bb18d
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+
+/**
+ * Deserializing a string valued object
+ */
+public class SqlDateDeserializer extends AbstractDeserializer {
+ private Class _cl;
+ private Constructor _constructor;
+
+ public SqlDateDeserializer(Class cl)
+ throws NoSuchMethodException
+ {
+ _cl = cl;
+ _constructor = cl.getConstructor(new Class[] { long.class });
+ }
+
+ public Class getType()
+ {
+ return _cl;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ int ref = in.addRef(null);
+
+ long initValue = Long.MIN_VALUE;
+
+ while (! in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ initValue = in.readUTCDate();
+ else
+ in.readString();
+ }
+
+ in.readMapEnd();
+
+ Object value = create(initValue);
+
+ in.setRef(ref, value);
+
+ return value;
+ }
+
+ public Object readObject(AbstractHessianInput in, String []fieldNames)
+ throws IOException
+ {
+ int ref = in.addRef(null);
+
+ long initValue = Long.MIN_VALUE;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String key = fieldNames[i];
+
+ if (key.equals("value"))
+ initValue = in.readUTCDate();
+ else
+ in.readObject();
+ }
+
+ Object value = create(initValue);
+
+ in.setRef(ref, value);
+
+ return value;
+ }
+
+ private Object create(long initValue)
+ throws IOException
+ {
+ if (initValue == Long.MIN_VALUE)
+ throw new IOException(_cl.getName() + " expects name.");
+
+ try {
+ return _constructor.newInstance(new Object[] { new Long(initValue) });
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java
new file mode 100644
index 0000000000..76bae31571
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * Serializing a sql date object.
+ */
+public class SqlDateSerializer extends AbstractSerializer
+{
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (obj == null)
+ out.writeNull();
+ else {
+ Class cl = obj.getClass();
+
+ if (out.addRef(obj))
+ return;
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ out.writeString("value");
+ out.writeUTCDate(((Date) obj).getTime());
+ out.writeMapEnd();
+ }
+ else {
+ if (ref == -1) {
+ out.writeInt(1);
+ out.writeString("value");
+ out.writeObjectBegin(cl.getName());
+ }
+
+ out.writeUTCDate(((Date) obj).getTime());
+ }
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java
new file mode 100644
index 0000000000..1918d7321e
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.*;
+import java.util.HashMap;
+
+/**
+ * Deserializing a JDK 1.4 StackTraceElement
+ */
+public class StackTraceElementDeserializer extends JavaDeserializer {
+ public StackTraceElementDeserializer()
+ {
+ super(StackTraceElement.class);
+ }
+
+ @Override
+ protected Object instantiate()
+ throws Exception
+ {
+ return new StackTraceElement("", "", "", 0);
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java
new file mode 100644
index 0000000000..f142def6d8
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+
+/**
+ * Deserializing a string valued object
+ */
+public class StringValueDeserializer extends AbstractDeserializer {
+ private Class _cl;
+ private Constructor _constructor;
+
+ public StringValueDeserializer(Class cl)
+ {
+ try {
+ _cl = cl;
+ _constructor = cl.getConstructor(new Class[] { String.class });
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Class getType()
+ {
+ return _cl;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ String value = null;
+
+ while (! in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ value = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object object = create(value);
+
+ in.addRef(object);
+
+ return object;
+ }
+
+ public Object readObject(AbstractHessianInput in, String []fieldNames)
+ throws IOException
+ {
+ String value = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i]))
+ value = in.readString();
+ else
+ in.readObject();
+ }
+
+ Object object = create(value);
+
+ in.addRef(object);
+
+ return object;
+ }
+
+ private Object create(String value)
+ throws IOException
+ {
+ if (value == null)
+ throw new IOException(_cl.getName() + " expects name.");
+
+ try {
+ return _constructor.newInstance(new Object[] { value });
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java
new file mode 100644
index 0000000000..0e04b07788
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Serializing a remote object.
+ */
+public class StringValueSerializer extends AbstractSerializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (obj == null)
+ out.writeNull();
+ else {
+ if (out.addRef(obj))
+ return;
+
+ Class cl = obj.getClass();
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ out.writeString("value");
+ out.writeString(obj.toString());
+ out.writeMapEnd();
+ }
+ else {
+ if (ref == -1) {
+ out.writeInt(1);
+ out.writeString("value");
+ out.writeObjectBegin(cl.getName());
+ }
+
+ out.writeString(obj.toString());
+ }
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java
new file mode 100644
index 0000000000..391dc1bb0f
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2001-2004 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 "Burlap", "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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class ThrowableSerializer extends JavaSerializer {
+ public ThrowableSerializer(Class cl, ClassLoader loader)
+ {
+ super(cl, loader);
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ Throwable e = (Throwable) obj;
+
+ e.getStackTrace();
+
+ super.writeObject(obj, out);
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java
new file mode 100644
index 0000000000..ba05a47c5d
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializing a string valued object
+ */
+abstract public class ValueDeserializer extends AbstractDeserializer {
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ String initValue = null;
+
+ while (! in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ initValue = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ return create(initValue);
+ }
+
+ public Object readObject(AbstractHessianInput in, String []fieldNames)
+ throws IOException
+ {
+ String initValue = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i]))
+ initValue = in.readString();
+ else
+ in.readObject();
+ }
+
+ return create(initValue);
+ }
+
+ abstract Object create(String value)
+ throws IOException;
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/security/X509Encryption.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/security/X509Encryption.java
new file mode 100644
index 0000000000..6a0b62211c
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/security/X509Encryption.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.security;
+
+import java.security.*;
+import java.security.cert.*;
+import java.util.*;
+import javax.crypto.*;
+
+import java.io.*;
+
+import com.alibaba.com.caucho.hessian.io.*;
+
+public class X509Encryption extends HessianEnvelope {
+ private String _algorithm = "AES";
+
+ // certificate for encryption/decryption
+ private X509Certificate _cert;
+
+ // private key for decryption
+ private PrivateKey _privateKey;
+
+ private SecureRandom _secureRandom;
+
+ public X509Encryption()
+ {
+ }
+
+ /**
+ * Sets the encryption algorithm for the content.
+ */
+ public void setAlgorithm(String algorithm)
+ {
+ if (algorithm == null)
+ throw new NullPointerException();
+
+ _algorithm = algorithm;
+ }
+
+ /**
+ * Gets the encryption algorithm for the content.
+ */
+ public String getAlgorithm()
+ {
+ return _algorithm;
+ }
+
+ /**
+ * The X509 certificate to obtain the public key of the recipient.
+ */
+ public X509Certificate getCertificate()
+ {
+ return _cert;
+ }
+
+ /**
+ * The X509 certificate to obtain the public key of the recipient.
+ */
+ public void setCertificate(X509Certificate cert)
+ {
+ _cert = cert;
+ }
+
+ /**
+ * The private key for decryption.
+ */
+ public PrivateKey getPrivateKey()
+ {
+ return _privateKey;
+ }
+
+ /**
+ * The X509 certificate to obtain the public key of the recipient.
+ */
+ public void setPrivateKey(PrivateKey privateKey)
+ {
+ _privateKey = privateKey;
+ }
+
+ /**
+ * The random number generator for the shared secrets.
+ */
+ public SecureRandom getSecureRandom()
+ {
+ return _secureRandom;
+ }
+
+ /**
+ * The random number generator for the shared secrets.
+ */
+ public void setSecureRandom(SecureRandom random)
+ {
+ _secureRandom = random;
+ }
+
+ public Hessian2Output wrap(Hessian2Output out)
+ throws IOException
+ {
+ if (_cert == null)
+ throw new IOException("X509Encryption.wrap requires a certificate");
+
+ OutputStream os = new EncryptOutputStream(out);
+
+ Hessian2Output filterOut = new Hessian2Output(os);
+
+ filterOut.setCloseStreamOnClose(true);
+
+ return filterOut;
+ }
+
+ public Hessian2Input unwrap(Hessian2Input in)
+ throws IOException
+ {
+ if (_privateKey == null)
+ throw new IOException("X509Encryption.unwrap requires a private key");
+
+ if (_cert == null)
+ throw new IOException("X509Encryption.unwrap requires a certificate");
+
+ int version = in.readEnvelope();
+
+ String method = in.readMethod();
+
+ if (! method.equals(getClass().getName()))
+ throw new IOException("expected hessian Envelope method '" +
+ getClass().getName() + "' at '" + method + "'");
+
+ return unwrapHeaders(in);
+ }
+
+ public Hessian2Input unwrapHeaders(Hessian2Input in)
+ throws IOException
+ {
+ if (_privateKey == null)
+ throw new IOException("X509Encryption.unwrap requires a private key");
+
+ if (_cert == null)
+ throw new IOException("X509Encryption.unwrap requires a certificate");
+
+ InputStream is = new EncryptInputStream(in);
+
+ Hessian2Input filter = new Hessian2Input(is);
+
+ filter.setCloseStreamOnClose(true);
+
+ return filter;
+ }
+
+ class EncryptOutputStream extends OutputStream {
+ private Hessian2Output _out;
+
+ private Cipher _cipher;
+ private OutputStream _bodyOut;
+ private CipherOutputStream _cipherOut;
+
+ EncryptOutputStream(Hessian2Output out)
+ throws IOException
+ {
+ try {
+ _out = out;
+
+ KeyGenerator keyGen = KeyGenerator.getInstance(_algorithm);
+
+ if (_secureRandom != null)
+ keyGen.init(_secureRandom);
+
+ SecretKey sharedKey = keyGen.generateKey();
+
+ _out = out;
+
+ _out.startEnvelope(X509Encryption.class.getName());
+
+ PublicKey publicKey = _cert.getPublicKey();
+
+ byte []encoded = publicKey.getEncoded();
+ MessageDigest md = MessageDigest.getInstance("SHA1");
+ md.update(encoded);
+ byte []fingerprint = md.digest();
+
+ String keyAlgorithm = publicKey.getAlgorithm();
+ Cipher keyCipher = Cipher.getInstance(keyAlgorithm);
+ if (_secureRandom != null)
+ keyCipher.init(Cipher.WRAP_MODE, _cert, _secureRandom);
+ else
+ keyCipher.init(Cipher.WRAP_MODE, _cert);
+
+ byte []encKey = keyCipher.wrap(sharedKey);
+
+ _out.writeInt(4);
+
+ _out.writeString("algorithm");
+ _out.writeString(_algorithm);
+ _out.writeString("fingerprint");
+ _out.writeBytes(fingerprint);
+ _out.writeString("key-algorithm");
+ _out.writeString(keyAlgorithm);
+ _out.writeString("key");
+ _out.writeBytes(encKey);
+
+ _bodyOut = _out.getBytesOutputStream();
+
+ _cipher = Cipher.getInstance(_algorithm);
+ if (_secureRandom != null)
+ _cipher.init(Cipher.ENCRYPT_MODE, sharedKey, _secureRandom);
+ else
+ _cipher.init(Cipher.ENCRYPT_MODE, sharedKey);
+
+ _cipherOut = new CipherOutputStream(_bodyOut, _cipher);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void write(int ch)
+ throws IOException
+ {
+ _cipherOut.write(ch);
+ }
+
+ public void write(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ _cipherOut.write(buffer, offset, length);
+ }
+
+ public void close()
+ throws IOException
+ {
+ Hessian2Output out = _out;
+ _out = null;
+
+ if (out != null) {
+ _cipherOut.close();
+ _bodyOut.close();
+
+ out.writeInt(0);
+ out.completeEnvelope();
+ out.close();
+ }
+ }
+ }
+
+ class EncryptInputStream extends InputStream {
+ private Hessian2Input _in;
+
+ private Cipher _cipher;
+ private InputStream _bodyIn;
+ private CipherInputStream _cipherIn;
+
+ EncryptInputStream(Hessian2Input in)
+ throws IOException
+ {
+ try {
+ _in = in;
+
+ byte []fingerprint = null;
+ String keyAlgorithm = null;
+ String algorithm = null;
+ byte []encKey = null;
+
+ int len = in.readInt();
+
+ for (int i = 0; i < len; i++) {
+ String header = in.readString();
+
+ if ("fingerprint".equals(header))
+ fingerprint = in.readBytes();
+ else if ("key-algorithm".equals(header))
+ keyAlgorithm = in.readString();
+ else if ("algorithm".equals(header))
+ algorithm = in.readString();
+ else if ("key".equals(header))
+ encKey = in.readBytes();
+ else
+ throw new IOException("'" + header + "' is an unexpected header");
+ }
+
+ Cipher keyCipher = Cipher.getInstance(keyAlgorithm);
+ keyCipher.init(Cipher.UNWRAP_MODE, _privateKey);
+
+ Key key = keyCipher.unwrap(encKey, algorithm, Cipher.SECRET_KEY);
+ _bodyIn = _in.readInputStream();
+
+ _cipher = Cipher.getInstance(algorithm);
+ _cipher.init(Cipher.DECRYPT_MODE, key);
+
+ _cipherIn = new CipherInputStream(_bodyIn, _cipher);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int read()
+ throws IOException
+ {
+ return _cipherIn.read();
+ }
+
+ public int read(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ return _cipherIn.read(buffer, offset, length);
+ }
+
+ public void close()
+ throws IOException
+ {
+ Hessian2Input in = _in;
+ _in = null;
+
+ if (in != null) {
+ _cipherIn.close();
+ _bodyIn.close();
+
+ int len = in.readInt();
+
+ if (len != 0)
+ throw new IOException("Unexpected footer");
+
+ in.completeEnvelope();
+
+ in.close();
+ }
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/security/X509Signature.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/security/X509Signature.java
new file mode 100644
index 0000000000..77b19bb043
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/security/X509Signature.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2001-2004 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.alibaba.com.caucho.hessian.security;
+
+import java.security.*;
+import java.security.cert.*;
+import java.util.*;
+import javax.crypto.*;
+
+import java.io.*;
+
+import com.alibaba.com.caucho.hessian.io.*;
+
+public class X509Signature extends HessianEnvelope {
+ private String _algorithm = "HmacSHA256";
+ private X509Certificate _cert;
+ private PrivateKey _privateKey;
+ private SecureRandom _secureRandom;
+
+ public X509Signature()
+ {
+ }
+
+ /**
+ * Sets the encryption algorithm for the content.
+ */
+ public void setAlgorithm(String algorithm)
+ {
+ if (algorithm == null)
+ throw new NullPointerException();
+
+ _algorithm = algorithm;
+ }
+
+ /**
+ * Gets the encryption algorithm for the content.
+ */
+ public String getAlgorithm()
+ {
+ return _algorithm;
+ }
+
+ /**
+ * The X509 certificate to obtain the public key of the recipient.
+ */
+ public X509Certificate getCertificate()
+ {
+ return _cert;
+ }
+
+ /**
+ * The X509 certificate to obtain the public key of the recipient.
+ */
+ public void setCertificate(X509Certificate cert)
+ {
+ _cert = cert;
+ }
+
+ /**
+ * The key to obtain the private key of the recipient.
+ */
+ public PrivateKey getPrivateKey()
+ {
+ return _privateKey;
+ }
+
+ /**
+ * The private key.
+ */
+ public void setPrivateKey(PrivateKey key)
+ {
+ _privateKey = key;
+ }
+
+ /**
+ * The random number generator for the shared secrets.
+ */
+ public SecureRandom getSecureRandom()
+ {
+ return _secureRandom;
+ }
+
+ /**
+ * The random number generator for the shared secrets.
+ */
+ public void setSecureRandom(SecureRandom random)
+ {
+ _secureRandom = random;
+ }
+
+ public Hessian2Output wrap(Hessian2Output out)
+ throws IOException
+ {
+ if (_privateKey == null)
+ throw new IOException("X509Signature.wrap requires a private key");
+
+ if (_cert == null)
+ throw new IOException("X509Signature.wrap requires a certificate");
+
+ OutputStream os = new SignatureOutputStream(out);
+
+ Hessian2Output filterOut = new Hessian2Output(os);
+
+ filterOut.setCloseStreamOnClose(true);
+
+ return filterOut;
+ }
+
+ public Hessian2Input unwrap(Hessian2Input in)
+ throws IOException
+ {
+ if (_cert == null)
+ throw new IOException("X509Signature.unwrap requires a certificate");
+
+ int version = in.readEnvelope();
+
+ String method = in.readMethod();
+
+ if (! method.equals(getClass().getName()))
+ throw new IOException("expected hessian Envelope method '" +
+ getClass().getName() + "' at '" + method + "'");
+
+ return unwrapHeaders(in);
+ }
+
+ public Hessian2Input unwrapHeaders(Hessian2Input in)
+ throws IOException
+ {
+ if (_cert == null)
+ throw new IOException("X509Signature.unwrap requires a certificate");
+
+ InputStream is = new SignatureInputStream(in);
+
+ Hessian2Input filter = new Hessian2Input(is);
+
+ filter.setCloseStreamOnClose(true);
+
+ return filter;
+ }
+
+ class SignatureOutputStream extends OutputStream {
+ private Hessian2Output _out;
+ private OutputStream _bodyOut;
+ private Mac _mac;
+
+ SignatureOutputStream(Hessian2Output out)
+ throws IOException
+ {
+ try {
+ KeyGenerator keyGen = KeyGenerator.getInstance(_algorithm);
+
+ if (_secureRandom != null)
+ keyGen.init(_secureRandom);
+
+ SecretKey sharedKey = keyGen.generateKey();
+
+ _out = out;
+
+ _out.startEnvelope(X509Signature.class.getName());
+
+ PublicKey publicKey = _cert.getPublicKey();
+
+ byte []encoded = publicKey.getEncoded();
+ MessageDigest md = MessageDigest.getInstance("SHA1");
+ md.update(encoded);
+ byte []fingerprint = md.digest();
+
+ String keyAlgorithm = _privateKey.getAlgorithm();
+ Cipher keyCipher = Cipher.getInstance(keyAlgorithm);
+ keyCipher.init(Cipher.WRAP_MODE, _privateKey);
+
+ byte []encKey = keyCipher.wrap(sharedKey);
+
+ _out.writeInt(4);
+ _out.writeString("algorithm");
+ _out.writeString(_algorithm);
+ _out.writeString("fingerprint");
+ _out.writeBytes(fingerprint);
+ _out.writeString("key-algorithm");
+ _out.writeString(keyAlgorithm);
+ _out.writeString("key");
+ _out.writeBytes(encKey);
+
+ _mac = Mac.getInstance(_algorithm);
+ _mac.init(sharedKey);
+
+ _bodyOut = _out.getBytesOutputStream();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void write(int ch)
+ throws IOException
+ {
+ _bodyOut.write(ch);
+ _mac.update((byte) ch);
+ }
+
+ public void write(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ _bodyOut.write(buffer, offset, length);
+ _mac.update(buffer, offset, length);
+ }
+
+ public void close()
+ throws IOException
+ {
+ Hessian2Output out = _out;
+ _out = null;
+
+ if (out == null)
+ return;
+
+ _bodyOut.close();
+
+ byte []sig = _mac.doFinal();
+
+ out.writeInt(1);
+ out.writeString("signature");
+ out.writeBytes(sig);
+
+ out.completeEnvelope();
+ out.close();
+ }
+ }
+
+ class SignatureInputStream extends InputStream {
+ private Hessian2Input _in;
+
+ private Mac _mac;
+ private InputStream _bodyIn;
+ private CipherInputStream _cipherIn;
+
+ SignatureInputStream(Hessian2Input in)
+ throws IOException
+ {
+ try {
+ _in = in;
+
+ byte []fingerprint = null;
+ String keyAlgorithm = null;
+ String algorithm = null;
+ byte []encKey = null;
+
+ int len = in.readInt();
+
+ for (int i = 0; i < len; i++) {
+ String header = in.readString();
+
+ if ("fingerprint".equals(header))
+ fingerprint = in.readBytes();
+ else if ("key-algorithm".equals(header))
+ keyAlgorithm = in.readString();
+ else if ("algorithm".equals(header))
+ algorithm = in.readString();
+ else if ("key".equals(header))
+ encKey = in.readBytes();
+ else
+ throw new IOException("'" + header + "' is an unexpected header");
+ }
+
+ Cipher keyCipher = Cipher.getInstance(keyAlgorithm);
+ keyCipher.init(Cipher.UNWRAP_MODE, _cert);
+
+ Key key = keyCipher.unwrap(encKey, algorithm, Cipher.SECRET_KEY);
+ _bodyIn = _in.readInputStream();
+
+ _mac = Mac.getInstance(algorithm);
+ _mac.init(key);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int read()
+ throws IOException
+ {
+ int ch = _bodyIn.read();
+
+ if (ch < 0)
+ return ch;
+
+ _mac.update((byte) ch);
+
+ return ch;
+ }
+
+ public int read(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ int len = _bodyIn.read(buffer, offset, length);
+
+ if (len < 0)
+ return len;
+
+ _mac.update(buffer, offset, len);
+
+ return len;
+ }
+
+ public void close()
+ throws IOException
+ {
+ Hessian2Input in = _in;
+ _in = null;
+
+ if (in != null) {
+ _bodyIn.close();
+
+ int len = in.readInt();
+ byte []signature = null;
+
+ for (int i = 0; i < len; i++) {
+ String header = in.readString();
+
+ if ("signature".equals(header))
+ signature = in.readBytes();
+ }
+
+ in.completeEnvelope();
+ in.close();
+
+
+ if (signature == null)
+ throw new IOException("Expected signature");
+
+ byte []sig = _mac.doFinal();
+
+ if (sig.length != signature.length)
+ throw new IOException("mismatched signature");
+
+ for (int i = 0; i < sig.length; i++) {
+ if (signature[i] != sig[i])
+ throw new IOException("mismatched signature");
+ }
+
+ // XXX: save principal
+ }
+ }
+ }
+}
diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java
new file mode 100644
index 0000000000..a17908952c
--- /dev/null
+++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java
@@ -0,0 +1,252 @@
+/*
+ * 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 "Burlap", "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.alibaba.com.caucho.hessian.util;
+
+/**
+ * The IntMap provides a simple hashmap from keys to integers. The API is
+ * an abbreviation of the HashMap collection API.
+ *
+ * The convenience of IntMap is avoiding all the silly wrapping of + * integers. + */ +public class IdentityIntMap { + /** + * Encoding of a null entry. Since NULL is equal to Integer.MIN_VALUE, + * it's impossible to distinguish between the two. + */ + public final static int NULL = 0xdeadbeef; // Integer.MIN_VALUE + 1; + + private static final Object DELETED = new Object(); + + private Object []_keys; + private int []_values; + + private int _size; + private int _mask; + + /** + * Create a new IntMap. Default size is 16. + */ + public IdentityIntMap() + { + _keys = new Object[256]; + _values = new int[256]; + + _mask = _keys.length - 1; + _size = 0; + } + + /** + * Clear the hashmap. + */ + public void clear() + { + Object []keys = _keys; + int []values = _values; + + for (int i = keys.length - 1; i >= 0; i--) { + keys[i] = null; + values[i] = 0; + } + + _size = 0; + } + /** + * Returns the current number of entries in the map. + */ + public int size() + { + return _size; + } + + /** + * Puts a new value in the property table with the appropriate flags + */ + public int get(Object key) + { + int mask = _mask; + int hash = System.identityHashCode(key) % mask & mask; + + Object []keys = _keys; + + while (true) { + Object mapKey = keys[hash]; + + if (mapKey == null) + return NULL; + else if (mapKey == key) + return _values[hash]; + + hash = (hash + 1) % mask; + } + } + + /** + * Expands the property table + */ + private void resize(int newSize) + { + Object []newKeys = new Object[newSize]; + int []newValues = new int[newSize]; + + int mask = _mask = newKeys.length - 1; + + Object []keys = _keys; + int values[] = _values; + + for (int i = keys.length - 1; i >= 0; i--) { + Object key = keys[i]; + + if (key == null || key == DELETED) + continue; + + int hash = System.identityHashCode(key) % mask & mask; + + while (true) { + if (newKeys[hash] == null) { + newKeys[hash] = key; + newValues[hash] = values[i]; + break; + } + + hash = (hash + 1) % mask; + } + } + + _keys = newKeys; + _values = newValues; + } + + /** + * Puts a new value in the property table with the appropriate flags + */ + public int put(Object key, int value) + { + int mask = _mask; + int hash = System.identityHashCode(key) % mask & mask; + + Object []keys = _keys; + + while (true) { + Object testKey = keys[hash]; + + if (testKey == null || testKey == DELETED) { + keys[hash] = key; + _values[hash] = value; + + _size++; + + if (keys.length <= 4 * _size) + resize(4 * keys.length); + + return NULL; + } + else if (key != testKey) { + hash = (hash + 1) % mask; + + continue; + } + else { + int old = _values[hash]; + + _values[hash] = value; + + return old; + } + } + } + + /** + * Deletes the entry. Returns true if successful. + */ + public int remove(Object key) + { + int mask = _mask; + int hash = System.identityHashCode(key) % mask & mask; + + while (true) { + Object mapKey = _keys[hash]; + + if (mapKey == null) + return NULL; + else if (mapKey == key) { + _keys[hash] = DELETED; + + _size--; + + return _values[hash]; + } + + hash = (hash + 1) % mask; + } + } + + public String toString() + { + StringBuffer sbuf = new StringBuffer(); + + sbuf.append("IntMap["); + boolean isFirst = true; + + for (int i = 0; i <= _mask; i++) { + if (_keys[i] != null && _keys[i] != DELETED) { + if (! isFirst) + sbuf.append(", "); + + isFirst = false; + sbuf.append(_keys[i]); + sbuf.append(":"); + sbuf.append(_values[i]); + } + } + sbuf.append("]"); + + return sbuf.toString(); + } +} diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java new file mode 100644 index 0000000000..c84bbd4dc5 --- /dev/null +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java @@ -0,0 +1,252 @@ +/* + * 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 "Burlap", "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.alibaba.com.caucho.hessian.util; + +/** + * The IntMap provides a simple hashmap from keys to integers. The API is + * an abbreviation of the HashMap collection API. + * + *
The convenience of IntMap is avoiding all the silly wrapping of
+ * integers.
+ */
+public class IntMap {
+ /**
+ * Encoding of a null entry. Since NULL is equal to Integer.MIN_VALUE,
+ * it's impossible to distinguish between the two.
+ */
+ public final static int NULL = 0xdeadbeef; // Integer.MIN_VALUE + 1;
+
+ private static final Object DELETED = new Object();
+
+ private Object []_keys;
+ private int []_values;
+
+ private int _size;
+ private int _mask;
+
+ /**
+ * Create a new IntMap. Default size is 16.
+ */
+ public IntMap()
+ {
+ _keys = new Object[256];
+ _values = new int[256];
+
+ _mask = _keys.length - 1;
+ _size = 0;
+ }
+
+ /**
+ * Clear the hashmap.
+ */
+ public void clear()
+ {
+ Object []keys = _keys;
+ int []values = _values;
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ keys[i] = null;
+ values[i] = 0;
+ }
+
+ _size = 0;
+ }
+ /**
+ * Returns the current number of entries in the map.
+ */
+ public int size()
+ {
+ return _size;
+ }
+
+ /**
+ * Puts a new value in the property table with the appropriate flags
+ */
+ public int get(Object key)
+ {
+ int mask = _mask;
+ int hash = key.hashCode() % mask & mask;
+
+ Object []keys = _keys;
+
+ while (true) {
+ Object mapKey = keys[hash];
+
+ if (mapKey == null)
+ return NULL;
+ else if (mapKey == key || mapKey.equals(key))
+ return _values[hash];
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ /**
+ * Expands the property table
+ */
+ private void resize(int newSize)
+ {
+ Object []newKeys = new Object[newSize];
+ int []newValues = new int[newSize];
+
+ int mask = _mask = newKeys.length - 1;
+
+ Object []keys = _keys;
+ int values[] = _values;
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ Object key = keys[i];
+
+ if (key == null || key == DELETED)
+ continue;
+
+ int hash = key.hashCode() % mask & mask;
+
+ while (true) {
+ if (newKeys[hash] == null) {
+ newKeys[hash] = key;
+ newValues[hash] = values[i];
+ break;
+ }
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ _keys = newKeys;
+ _values = newValues;
+ }
+
+ /**
+ * Puts a new value in the property table with the appropriate flags
+ */
+ public int put(Object key, int value)
+ {
+ int mask = _mask;
+ int hash = key.hashCode() % mask & mask;
+
+ Object []keys = _keys;
+
+ while (true) {
+ Object testKey = keys[hash];
+
+ if (testKey == null || testKey == DELETED) {
+ keys[hash] = key;
+ _values[hash] = value;
+
+ _size++;
+
+ if (keys.length <= 4 * _size)
+ resize(4 * keys.length);
+
+ return NULL;
+ }
+ else if (key != testKey && ! key.equals(testKey)) {
+ hash = (hash + 1) % mask;
+
+ continue;
+ }
+ else {
+ int old = _values[hash];
+
+ _values[hash] = value;
+
+ return old;
+ }
+ }
+ }
+
+ /**
+ * Deletes the entry. Returns true if successful.
+ */
+ public int remove(Object key)
+ {
+ int mask = _mask;
+ int hash = key.hashCode() % mask & mask;
+
+ while (true) {
+ Object mapKey = _keys[hash];
+
+ if (mapKey == null)
+ return NULL;
+ else if (mapKey == key) {
+ _keys[hash] = DELETED;
+
+ _size--;
+
+ return _values[hash];
+ }
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer sbuf = new StringBuffer();
+
+ sbuf.append("IntMap[");
+ boolean isFirst = true;
+
+ for (int i = 0; i <= _mask; i++) {
+ if (_keys[i] != null && _keys[i] != DELETED) {
+ if (! isFirst)
+ sbuf.append(", ");
+
+ isFirst = false;
+ sbuf.append(_keys[i]);
+ sbuf.append(":");
+ sbuf.append(_values[i]);
+ }
+ }
+ sbuf.append("]");
+
+ return sbuf.toString();
+ }
+}
diff --git a/pom.xml b/pom.xml
index 308901ddcf..7cdbfb61a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,11 +16,12 @@