diff --git a/edexOsgi/build.edex/esb/bin/start.sh b/edexOsgi/build.edex/esb/bin/start.sh
index 8bfd54ed3c..2c176ed8ba 100644
--- a/edexOsgi/build.edex/esb/bin/start.sh
+++ b/edexOsgi/build.edex/esb/bin/start.sh
@@ -94,7 +94,7 @@ export AMQP_SPEC=$awips_home/python/share/amqp/amqp.0-10.xml
#read and interpret the command line arguments
#-------------------------------------------------------------------------
CONSOLE_FLAG=on
-CONSOLE_LOGLEVEL=INFO
+CONSOLE_LOGLEVEL=DEBUG
DEBUG_FLAG=off
PROFILE_FLAG=off
HIGH_MEM_FLAG=off
diff --git a/edexOsgi/build.edex/esb/bin/yajsw/wrapper.jar b/edexOsgi/build.edex/esb/bin/yajsw/wrapper.jar
index 7dc5b8c284..6b7c007d02 100644
Binary files a/edexOsgi/build.edex/esb/bin/yajsw/wrapper.jar and b/edexOsgi/build.edex/esb/bin/yajsw/wrapper.jar differ
diff --git a/edexOsgi/build.edex/esb/bin/yajsw/wrapperApp.jar b/edexOsgi/build.edex/esb/bin/yajsw/wrapperApp.jar
index 9f862241cc..35a55099c5 100644
Binary files a/edexOsgi/build.edex/esb/bin/yajsw/wrapperApp.jar and b/edexOsgi/build.edex/esb/bin/yajsw/wrapperApp.jar differ
diff --git a/edexOsgi/build.edex/esb/conf/wrapper.conf b/edexOsgi/build.edex/esb/conf/wrapper.conf
index 0632caa799..4b6295f097 100644
--- a/edexOsgi/build.edex/esb/conf/wrapper.conf
+++ b/edexOsgi/build.edex/esb/conf/wrapper.conf
@@ -181,7 +181,7 @@ wrapper.trigger.action=RESTART
wrapper.console.format=M
# Log Level for console output. (See docs for log levels)
-wrapper.console.loglevel=DEBUG
+wrapper.console.loglevel=${CONSOLE_LOGLEVEL}
# Log file to use for wrapper output logging.
wrapper.logfile=${EDEX_HOME}/logs/edex-${EDEX_RUN_MODE}-YYYYMMDD.log
diff --git a/edexOsgi/build.edex/yajsw-stable-11.04.tar b/edexOsgi/build.edex/yajsw-stable-11.04.tar
index c3feabf6b6..b6d1b00fbf 100644
Binary files a/edexOsgi/build.edex/yajsw-stable-11.04.tar and b/edexOsgi/build.edex/yajsw-stable-11.04.tar differ
diff --git a/javaUtilities/yajsw/.classpath b/javaUtilities/yajsw/.classpath
new file mode 100644
index 0000000000..3120509882
--- /dev/null
+++ b/javaUtilities/yajsw/.classpath
@@ -0,0 +1,46 @@
+
+ The main goal of this package is to allow to filter connections based on IP rules.
+ * The main interface is {@link IpFilteringHandler} which all filters will extend. Two IP filtering are proposed:
+ * i.e.:
+ * CIDR subnet = newCIDR ("10.10.10.0/24"); or
+ * CIDR subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or
+ * CIDR subnet = newCIDR ("10.10.10.0/255.255.255.0");
+ * @param cidr
+ * @return the generated CIDR
+ * @throws UnknownHostException
+ */
+ public static CIDR newCIDR(String cidr) throws UnknownHostException
+ {
+ int p = cidr.indexOf("/");
+ if (p < 0)
+ {
+ throw new UnknownHostException("Invalid CIDR notation used: " + cidr);
+ }
+ String addrString = cidr.substring(0, p);
+ String maskString = cidr.substring(p + 1);
+ InetAddress addr = addressStringToInet(addrString);
+ int mask = 0;
+ if (maskString.indexOf(".") < 0)
+ {
+ mask = parseInt(maskString, -1);
+ }
+ else
+ {
+ mask = getNetMask(maskString);
+ if (addr instanceof Inet6Address)
+ {
+ mask += 96;
+ }
+ }
+ if (mask < 0)
+ {
+ throw new UnknownHostException("Invalid mask length used: " + maskString);
+ }
+ return newCIDR(addr, mask);
+ }
+
+ /** @return the baseAddress of the CIDR block. */
+ public InetAddress getBaseAddress()
+ {
+ return baseAddress;
+ }
+
+ /** @return the Mask length. */
+ public int getMask()
+ {
+ return cidrMask;
+ }
+
+ /** @return the textual CIDR notation. */
+ @Override
+ public String toString()
+ {
+ return baseAddress.getHostAddress() + "/" + cidrMask;
+ }
+
+ /** @return the end address of this block. */
+ public abstract InetAddress getEndAddress();
+
+ /**
+ * Compares the given InetAddress against the CIDR and returns true if
+ * the ip is in the subnet-ip-range and false if not.
+ * @param inetAddress
+ * @return returns true if the given IP address is inside the currently
+ * set network.
+ */
+ public abstract boolean contains(InetAddress inetAddress);
+
+ /** Convert an IPv4 or IPv6 textual representation into an
+ * InetAddress.
+ * @param addr
+ * @return the created InetAddress
+ * @throws UnknownHostException
+ */
+ private static InetAddress addressStringToInet(String addr) throws UnknownHostException
+ {
+ return InetAddress.getByName(addr);
+ }
+
+ /**
+ * Get the Subnet's Netmask in Decimal format.
+ * i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask
+ * @param netMask a network mask
+ * @return the integer CIDR mask
+ * */
+ private static int getNetMask(String netMask)
+ {
+ StringTokenizer nm = new StringTokenizer(netMask, ".");
+ int i = 0;
+ int[] netmask = new int[4];
+ while (nm.hasMoreTokens())
+ {
+ netmask[i] = Integer.parseInt(nm.nextToken());
+ i++;
+ }
+ int mask1 = 0;
+ for (i = 0; i < 4; i++)
+ {
+ mask1 += Integer.bitCount(netmask[i]);
+ }
+ return mask1;
+ }
+
+ /** @param intstr a string containing an integer.
+ * @param def the default if the string does not contain a valid
+ * integer.
+ * @return the inetAddress from the integer
+ */
+ private static int parseInt(String intstr, int def)
+ {
+ Integer res;
+ if (intstr == null)
+ {
+ return def;
+ }
+ try
+ {
+ res = Integer.decode(intstr);
+ }
+ catch (Exception e)
+ {
+ res = new Integer(def);
+ }
+ return res.intValue();
+ }
+
+ /**
+ * Compute a byte representation of IpV4 from a IpV6
+ * @param address
+ * @return the byte representation
+ * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4
+ */
+ public static byte[] getIpV4FromIpV6(Inet6Address address) throws IllegalArgumentException
+ {
+ byte[] baddr = address.getAddress();
+ for (int i = 0; i < 9; i++)
+ {
+ if (baddr[i] != 0)
+ {
+ throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context");
+ }
+ }
+ if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF)
+ {
+ throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context");
+ }
+ return new byte[]
+ {baddr[12], baddr[13], baddr[14], baddr[15]};
+ }
+
+ /**
+ * Compute a byte representation of IpV6 from a IpV4
+ * @param address
+ * @return the byte representation
+ * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4
+ */
+ public static byte[] getIpV6FromIpV4(Inet4Address address) throws IllegalArgumentException
+ {
+ byte[] baddr = address.getAddress();
+ return new byte[]
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]};
+ }
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/CIDR4.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/CIDR4.java
new file mode 100644
index 0000000000..245900f01b
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/CIDR4.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * @author frederic bregier
+ */
+public class CIDR4 extends CIDR
+{
+ /**
+ * The integer for the base address
+ */
+ private int addressInt;
+
+ /**
+ * The integer for the end address
+ */
+ private final int addressEndInt;
+
+ /**
+ * @param newaddr
+ * @param mask
+ */
+ protected CIDR4(Inet4Address newaddr, int mask)
+ {
+ cidrMask = mask;
+ addressInt = ipv4AddressToInt(newaddr);
+ int newmask = ipv4PrefixLengthToMask(mask);
+ addressInt &= newmask;
+ try
+ {
+ baseAddress = intToIPv4Address(addressInt);
+ }
+ catch (UnknownHostException e)
+ {
+ // this should never happen
+ }
+ addressEndInt = addressInt + ipv4PrefixLengthToLength(cidrMask) - 1;
+ }
+
+ @Override
+ public InetAddress getEndAddress()
+ {
+ try
+ {
+ return intToIPv4Address(addressEndInt);
+ }
+ catch (UnknownHostException e)
+ {
+ // this should never happen
+ return null;
+ }
+ }
+
+ public int compareTo(CIDR arg)
+ {
+ if (arg instanceof CIDR6)
+ {
+ byte[] address = getIpV4FromIpV6((Inet6Address) arg.baseAddress);
+ int net = ipv4AddressToInt(address);
+ if (net == addressInt && arg.cidrMask == cidrMask)
+ {
+ return 0;
+ }
+ if (net < addressInt)
+ {
+ return 1;
+ }
+ else if (net > addressInt)
+ {
+ return -1;
+ }
+ else if (arg.cidrMask < cidrMask)
+ {
+ return -1;
+ }
+ return 1;
+ }
+ CIDR4 o = (CIDR4) arg;
+ if (o.addressInt == addressInt && o.cidrMask == cidrMask)
+ {
+ return 0;
+ }
+ if (o.addressInt < addressInt)
+ {
+ return 1;
+ }
+ else if (o.addressInt > addressInt)
+ {
+ return -1;
+ }
+ else if (o.cidrMask < cidrMask)
+ {
+ // greater Mask means less IpAddresses so -1
+ return -1;
+ }
+ return 1;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.netty.handler.ipfilter.CIDR#contains(java.net.InetAddress)
+ */
+ @Override
+ public boolean contains(InetAddress inetAddress)
+ {
+ int search = ipv4AddressToInt(inetAddress);
+ return search >= addressInt && search <= addressEndInt;
+ }
+
+ /** Given an IPv4 baseAddress length, return the block length. I.e., a
+ * baseAddress length of 24 will return 256. */
+ private static int ipv4PrefixLengthToLength(int prefix_length)
+ {
+ return 1 << 32 - prefix_length;
+ }
+
+ /** Given a baseAddress length, return a netmask. I.e, a baseAddress length
+ * of 24 will return 0xFFFFFF00. */
+ private static int ipv4PrefixLengthToMask(int prefix_length)
+ {
+ return ~((1 << 32 - prefix_length) - 1);
+ }
+
+ /** Convert an integer into an (IPv4) InetAddress.
+ * @param addr
+ * @return the created InetAddress
+ * @throws UnknownHostException
+ * @throws UnknownHostException
+ */
+ private static InetAddress intToIPv4Address(int addr) throws UnknownHostException
+ {
+ byte[] a = new byte[4];
+ a[0] = (byte) (addr >> 24 & 0xFF);
+ a[1] = (byte) (addr >> 16 & 0xFF);
+ a[2] = (byte) (addr >> 8 & 0xFF);
+ a[3] = (byte) (addr & 0xFF);
+ return InetAddress.getByAddress(a);
+ }
+
+ /** Given an IPv4 address, convert it into an integer.
+ * @param addr
+ * @return the integer representation of the InetAddress
+ *
+ * @throws IllegalArgumentException if the address is really an
+ * IPv6 address.
+ */
+ private static int ipv4AddressToInt(InetAddress addr)
+ {
+ byte[] address = null;
+ if (addr instanceof Inet6Address)
+ {
+ address = getIpV4FromIpV6((Inet6Address) addr);
+ }
+ else
+ {
+ address = addr.getAddress();
+ }
+ return ipv4AddressToInt(address);
+ }
+
+ /** Given an IPv4 address as array of bytes, convert it into an integer.
+ * @param address
+ * @return the integer representation of the InetAddress
+ *
+ * @throws IllegalArgumentException if the address is really an
+ * IPv6 address.
+ */
+ private static int ipv4AddressToInt(byte[] address)
+ {
+ int net = 0;
+ for (byte addres : address)
+ {
+ net <<= 8;
+ net |= addres & 0xFF;
+ }
+ return net;
+ }
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/CIDR6.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/CIDR6.java
new file mode 100644
index 0000000000..e1cd064326
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/CIDR6.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.jboss.netty.logging.InternalLogger;
+import org.jboss.netty.logging.InternalLoggerFactory;
+
+/**
+ * @author frederic bregier
+ */
+public class CIDR6 extends CIDR
+{
+
+ private static final InternalLogger logger = InternalLoggerFactory.getInstance(CIDR6.class);
+
+ /**
+ * The big integer for the base address
+ */
+ private BigInteger addressBigInt;
+
+ /**
+ * The big integer for the end address
+ */
+ private final BigInteger addressEndBigInt;
+
+ /**
+ * @param newaddress
+ * @param newmask
+ */
+ protected CIDR6(Inet6Address newaddress, int newmask)
+ {
+ cidrMask = newmask;
+ addressBigInt = ipv6AddressToBigInteger(newaddress);
+ BigInteger mask = ipv6CidrMaskToMask(newmask);
+ try
+ {
+ addressBigInt = addressBigInt.and(mask);
+ baseAddress = bigIntToIPv6Address(addressBigInt);
+ }
+ catch (UnknownHostException e)
+ {
+ // this should never happen.
+ }
+ addressEndBigInt = addressBigInt.add(ipv6CidrMaskToBaseAddress(cidrMask)).subtract(BigInteger.ONE);
+ }
+
+ @Override
+ public InetAddress getEndAddress()
+ {
+ try
+ {
+ return bigIntToIPv6Address(addressEndBigInt);
+ }
+ catch (UnknownHostException e)
+ {
+ logger.error("invalid ip address calculated as an end address");
+ return null;
+ }
+ }
+
+ public int compareTo(CIDR arg)
+ {
+ if (arg instanceof CIDR4)
+ {
+ BigInteger net = ipv6AddressToBigInteger(arg.baseAddress);
+ int res = net.compareTo(addressBigInt);
+ if (res == 0)
+ {
+ if (arg.cidrMask == cidrMask)
+ {
+ return 0;
+ }
+ else if (arg.cidrMask < cidrMask)
+ {
+ return -1;
+ }
+ return 1;
+ }
+ return res;
+ }
+ CIDR6 o = (CIDR6) arg;
+ if (o.addressBigInt.equals(addressBigInt) && o.cidrMask == cidrMask)
+ {
+ return 0;
+ }
+ int res = o.addressBigInt.compareTo(addressBigInt);
+ if (res == 0)
+ {
+ if (o.cidrMask < cidrMask)
+ {
+ // greater Mask means less IpAddresses so -1
+ return -1;
+ }
+ return 1;
+ }
+ return res;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.netty.handler.ipfilter.CIDR#contains(java.net.InetAddress)
+ */
+ @Override
+ public boolean contains(InetAddress inetAddress)
+ {
+ BigInteger search = ipv6AddressToBigInteger(inetAddress);
+ return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0;
+ }
+
+ /** Given an IPv6 baseAddress length, return the block length. I.e., a
+ * baseAddress length of 96 will return 2**32. */
+ private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask)
+ {
+ return BigInteger.ONE.shiftLeft(128 - cidrMask);
+ }
+
+ private static BigInteger ipv6CidrMaskToMask(int cidrMask)
+ {
+ return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not();
+ }
+
+ /** Given an IPv6 address, convert it into a BigInteger.
+ * @param addr
+ * @return the integer representation of the InetAddress
+ *
+ * @throws IllegalArgumentException if the address is not an IPv6
+ * address.
+ */
+ private static BigInteger ipv6AddressToBigInteger(InetAddress addr)
+ {
+ byte[] ipv6;
+ if (addr instanceof Inet4Address)
+ {
+ ipv6 = getIpV6FromIpV4((Inet4Address) addr);
+ }
+ else
+ {
+ ipv6 = addr.getAddress();
+ }
+ if (ipv6[0] == -1)
+ {
+ return new BigInteger(1, ipv6);
+ }
+ return new BigInteger(ipv6);
+ }
+
+ /** Convert a big integer into an IPv6 address.
+ * @param addr
+ * @return the inetAddress from the integer
+ *
+ * @throws UnknownHostException if the big integer is too large,
+ * and thus an invalid IPv6 address.
+ */
+ private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException
+ {
+ byte[] a = new byte[16];
+ byte[] b = addr.toByteArray();
+ if (b.length > 16 && !(b.length == 17 && b[0] == 0))
+ {
+ throw new UnknownHostException("invalid IPv6 address (too big)");
+ }
+ if (b.length == 16)
+ {
+ return InetAddress.getByAddress(b);
+ }
+ // handle the case where the IPv6 address starts with "FF".
+ if (b.length == 17)
+ {
+ System.arraycopy(b, 1, a, 0, 16);
+ }
+ else
+ {
+ // copy the address into a 16 byte array, zero-filled.
+ int p = 16 - b.length;
+ for (int i = 0; i < b.length; i++)
+ {
+ a[p + i] = b[i];
+ }
+ }
+ return InetAddress.getByAddress(a);
+ }
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterListener.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterListener.java
new file mode 100644
index 0000000000..605ce143a8
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterListener.java
@@ -0,0 +1,74 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetSocketAddress;
+
+import org.jboss.netty.channel.ChannelEvent;
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelHandlerContext;
+
+/**
+ * The listener interface for receiving ipFilter events.
+ *
+ * @see IpFilteringHandler
+ *
+ * @author Ron
+ */
+public interface IpFilterListener
+{
+
+ /**
+ * Called when the channel has the CONNECTED status and the channel was allowed by a previous call to accept().
+ * This method enables your implementation to send a message back to the client before closing
+ * or whatever you need. This method returns a ChannelFuture on which the implementation
+ * can wait uninterruptibly before continuing.
+ * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned.
+ * @param ctx
+ * @param e
+ * @param inetSocketAddress the remote {@link InetSocketAddress} from client
+ * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed.
+ */
+ public ChannelFuture allowed(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress);
+
+ /**
+ * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept().
+ * This method enables your implementation to send a message back to the client before closing
+ * or whatever you need. This method returns a ChannelFuture on which the implementation
+ * will wait uninterruptibly before closing the channel.
+ * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned.
+ * @param ctx
+ * @param e
+ * @param inetSocketAddress the remote {@link InetSocketAddress} from client
+ * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed.
+ */
+ public ChannelFuture refused(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress);
+
+ /**
+ * Called in handleUpstream, if this channel was previously blocked,
+ * to check if whatever the event, it should be passed to the next entry in the pipeline.
+ * If one wants to not block events, just overridden this method by returning always true.
+ * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since
+ * those events come out before the CONNECTED event and so the possibility to filter the connection.
+ * @param ctx
+ * @param e
+ * @return True if the event should continue, False if the event should not continue
+ * since this channel was blocked by this filter
+ */
+ public boolean continues(ChannelHandlerContext ctx, ChannelEvent e);
+
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterRule.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterRule.java
new file mode 100644
index 0000000000..14e9c65e3e
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterRule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+/**
+ * This Interface defines an Ip Filter Rule.
+ *
+ * @author frederic bregier
+ *
+ */
+public interface IpFilterRule extends IpSet
+{
+ /**
+ *
+ * @return True if this Rule is an ALLOW rule
+ */
+ public boolean isAllowRule();
+
+ /**
+ *
+ * @return True if this Rule is a DENY rule
+ */
+ public boolean isDenyRule();
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterRuleHandler.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterRuleHandler.java
new file mode 100644
index 0000000000..67ad934f91
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilterRuleHandler.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.jboss.netty.channel.ChannelEvent;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipelineCoverage;
+
+/**
+ * Implementation of Filter of IP based on ALLOW and DENY rules.
+ *
+ * This implementation could be changed by implementing a new {@link IpFilterRule} than default
+ * {@link IpV4SubnetFilterRule} (IPV4 support only), {@link IpSubnetFilterRule} (IPV4 and IPV6 support) or {@link IpPatternFilterRule} (IP and host name string pattern support) .
+ *
+ * The check is done by going from step to step in the underlying array of IpFilterRule.
+ * Each {@link IpFilterRule} answers to the method accept if the {@link InetAddress} is accepted or not,
+ * according to its implementation. If an InetAddress arrives at the end of the list, as in Firewall
+ * usual rules, the InetAddress is therefore accepted by default.
+ *
+ *
+ *
+ * An empty list means allow all (no limitation).
+ * For efficiency reason, you should not add/remove too frequently IpFilterRules to/from this handler.
+ * You should prefer to replace an entry (set method) with an ALLOW/DENY ALL IpFilterRule
+ * if possible.
+ * This handler should be created only once and reused on every pipeline since it handles
+ * a global status of what is allowed or blocked.
+ *
+ * Note that {@link IpSubnetFilterRule} which supports IPV4 and IPV6 should be used with as much as
+ * possible no mixed IP protocol. Both IPV4 and IPV6 are supported but a mix (IpFilter in IPV6 notation
+ * and the address from the channel in IPV4, or the reverse) can lead to wrong result.
+ * @author frederic bregier
+ *
+ */
+@ChannelPipelineCoverage("all")
+public class IpFilterRuleHandler extends IpFilteringHandlerImpl
+{
+ /**
+ * List of {@link IpFilterRule}
+ */
+ private final CopyOnWriteArrayList
+ * Rule List Syntax:
+ *
+ *
+ * RuleList ::= Rule[,Rule]*
+ * Rule ::= AllowRule | BlockRule
+ * AllowRule ::= +Filter
+ * BlockRule ::= -Filter
+ * Filter ::= PatternFilter | CIDRFilter
+ * PatternFilter ::= @see PatternRule
+ * CIDRFilter ::= c:CIDRFilter
+ * CIDRFilter ::= @see CIDR.newCIDR(String)
+ *
+ *
+ * Example: allow only localhost:
+ *
+ * new IPFilterRuleHandler().addAll(new IpFilterRuleList("+n:localhost, -n:*"));
+ *
+ *
+ * @author Ron
+ */
+public class IpFilterRuleList extends ArrayList
+ * Users can add an {@link IpFilterListener} to add specific actions in case a connection is allowed or refused.
+ *
+ * @author Ron
+ */
+public interface IpFilteringHandler extends ChannelUpstreamHandler
+{
+
+ /**
+ * Sets the filter listener.
+ *
+ * @param listener the new ip filter listener
+ */
+ public void setIpFilterListener(IpFilterListener listener);
+
+ /**
+ * Remove the filter listener.
+ */
+ public void removeIpFilterListener();
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilteringHandlerImpl.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilteringHandlerImpl.java
new file mode 100644
index 0000000000..1a02376093
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpFilteringHandlerImpl.java
@@ -0,0 +1,203 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetSocketAddress;
+
+import org.jboss.netty.channel.ChannelEvent;
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelFutureListener;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.Channels;
+
+// TODO: Auto-generated Javadoc
+/**
+ * General class that handle Ip Filtering.
+ *
+ * @author frederic bregier
+ */
+public abstract class IpFilteringHandlerImpl implements IpFilteringHandler
+{
+
+ private IpFilterListener listener = null;
+
+ /**
+ * Called when the channel is connected. It returns True if the corresponding connection
+ * is to be allowed. Else it returns False.
+ * @param ctx
+ * @param e
+ * @param inetSocketAddress the remote {@link InetSocketAddress} from client
+ * @return True if the corresponding connection is allowed, else False.
+ * @throws Exception
+ */
+ protected abstract boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress)
+ throws Exception;
+
+ /**
+ * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept().
+ * This method enables your implementation to send a message back to the client before closing
+ * or whatever you need. This method returns a ChannelFuture on which the implementation
+ * will wait uninterruptibly before closing the channel.
+ * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned.
+ * @param ctx
+ * @param e
+ * @param inetSocketAddress the remote {@link InetSocketAddress} from client
+ * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed.
+ * @throws Exception
+ */
+ protected ChannelFuture handleRefusedChannel(ChannelHandlerContext ctx, ChannelEvent e,
+ InetSocketAddress inetSocketAddress) throws Exception
+ {
+ if (listener == null)
+ return null;
+ ChannelFuture result = listener.refused(ctx, e, inetSocketAddress);
+ return result;
+ }
+
+ protected ChannelFuture handleAllowedChannel(ChannelHandlerContext ctx, ChannelEvent e,
+ InetSocketAddress inetSocketAddress) throws Exception
+ {
+ if (listener == null)
+ return null;
+ ChannelFuture result = listener.allowed(ctx, e, inetSocketAddress);
+ return result;
+ }
+
+ /**
+ * Internal method to test if the current channel is blocked. Should not be overridden.
+ * @param ctx
+ * @return True if the current channel is blocked, else False
+ */
+ protected boolean isBlocked(ChannelHandlerContext ctx)
+ {
+ return ctx.getAttachment() != null;
+ }
+
+ /**
+ * Called in handleUpstream, if this channel was previously blocked,
+ * to check if whatever the event, it should be passed to the next entry in the pipeline.
+ * If one wants to not block events, just overridden this method by returning always true.
+ * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since
+ * those events come out before the CONNECTED event and so the possibility to filter the connection.
+ * @param ctx
+ * @param e
+ * @return True if the event should continue, False if the event should not continue
+ * since this channel was blocked by this filter
+ * @throws Exception
+ */
+ protected boolean continues(ChannelHandlerContext ctx, ChannelEvent e) throws Exception
+ {
+ if (listener != null)
+ return listener.continues(ctx, e);
+ else
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.netty.channel.ChannelUpstreamHandler#handleUpstream(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelEvent)
+ */
+ public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception
+ {
+ if (e instanceof ChannelStateEvent)
+ {
+ ChannelStateEvent evt = (ChannelStateEvent) e;
+ switch (evt.getState())
+ {
+ case OPEN :
+ case BOUND :
+ // Special case: OPEND and BOUND events are before CONNECTED,
+ // but CLOSED and UNBOUND events are after DISCONNECTED: should those events be blocked too?
+ if (isBlocked(ctx) && !continues(ctx, evt))
+ {
+ // don't pass to next level since channel was blocked early
+ return;
+ }
+ else
+ {
+ ctx.sendUpstream(e);
+ return;
+ }
+ case CONNECTED :
+ if (evt.getValue() != null)
+ {
+ // CONNECTED
+ InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress();
+ if (!accept(ctx, e, inetSocketAddress))
+ {
+ ctx.setAttachment(Boolean.TRUE);
+ ChannelFuture future = handleRefusedChannel(ctx, e, inetSocketAddress);
+ if (future != null)
+ {
+ future.addListener(ChannelFutureListener.CLOSE);
+ }
+ else
+ {
+ Channels.close(e.getChannel());
+ }
+ if (isBlocked(ctx) && !continues(ctx, evt))
+ {
+ // don't pass to next level since channel was blocked early
+ return;
+ }
+ }
+ else
+ {
+ handleAllowedChannel(ctx, e, inetSocketAddress);
+ }
+ // This channel is not blocked
+ ctx.setAttachment(null);
+ }
+ else
+ {
+ // DISCONNECTED
+ if (isBlocked(ctx) && !continues(ctx, evt))
+ {
+ // don't pass to next level since channel was blocked early
+ return;
+ }
+ }
+ break;
+ }
+ }
+ if (isBlocked(ctx) && !continues(ctx, e))
+ {
+ // don't pass to next level since channel was blocked early
+ return;
+ }
+ // Whatever it is, if not blocked, goes to the next level
+ ctx.sendUpstream(e);
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#setIpFilterListener(org.jboss.netty.handler.ipfilter.IpFilterListener)
+ */
+ public void setIpFilterListener(IpFilterListener listener)
+ {
+ this.listener = listener;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#removeIpFilterListener()
+ */
+ public void removeIpFilterListener()
+ {
+ this.listener = null;
+
+ }
+
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSet.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSet.java
new file mode 100644
index 0000000000..09f02d0d2c
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSet.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+
+/**
+ * This Interface defines an IpSet object.
+ *
+ * @author frederic bregier
+ *
+ */
+public interface IpSet
+{
+ /**
+ * Compares the given InetAddress against the IpSet and returns true if
+ * the InetAddress is contained in this Rule and false if not.
+ * @param inetAddress1
+ * @return returns true if the given IP address is contained in the current
+ * IpSet.
+ */
+ public boolean contains(InetAddress inetAddress1);
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSubnet.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSubnet.java
new file mode 100644
index 0000000000..c0e028836b
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSubnet.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * This class allows to check if an IP V4 or V6 Address is contained in a subnet.
+ *
+ * Supported IP V4 Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation)
+ * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
+ *
Example1:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example1 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ *
Example2:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example2 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ *
+ * Supported IP V6 Formats for the Subnets are: a:b:c:d:e:f:g:h/NN (CIDR-Notation)
+ * or any IPV6 notations (like a:b:c:d::/NN, a:b:c:d:e:f:w.x.y.z/NN)
+ * and (InetAddress,Mask) where Mask is a integer for CIDR-notation
+ * and (InetAddress,subnet).
+ *
Example1:
+ * IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");
+ * IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3::/24");
+ * System.out.println("Result: "+ ips.contains("1fff:0:0a88:85a3:0:0:ac1f:8001"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example1 bis:
+ * IpSubnet ips = new IpSubnet(inetAddress, 24);
+ * where inetAddress2 is 1fff:0:0a88:85a3:0:0:ac1f:8001
+ *
+ * @author frederic bregier
+ *
+ */
+public class IpSubnet implements IpSet, Comparable
+ * i.e.:
+ * IpSubnet subnet = new IpSubnet("10.10.10.0/24"); or
+ * IpSubnet subnet = new IpSubnet("10.10.10.0/255.255.255.0"); or
+ * IpSubnet subnet = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");
+ * @param netAddress a network address as string.
+ * @throws UnknownHostException
+ * */
+ public IpSubnet(String netAddress) throws UnknownHostException
+ {
+ cidr = CIDR.newCIDR(netAddress);
+ }
+
+ /**
+ * Create IpSubnet using the CIDR Notation
+ * @param inetAddress
+ * @param cidrNetMask
+ * @throws UnknownHostException
+ */
+ public IpSubnet(InetAddress inetAddress, int cidrNetMask) throws UnknownHostException
+ {
+ cidr = CIDR.newCIDR(inetAddress, cidrNetMask);
+ }
+
+ /**
+ * Create IpSubnet using the normal Notation
+ * @param inetAddress
+ * @param netMask
+ * @throws UnknownHostException
+ */
+ public IpSubnet(InetAddress inetAddress, String netMask) throws UnknownHostException
+ {
+ cidr = CIDR.newCIDR(inetAddress, netMask);
+ }
+
+ /**
+ * Compares the given IP-Address against the Subnet and returns true if
+ * the ip is in the subnet-ip-range and false if not.
+ * @param ipAddr an ipaddress
+ * @return returns true if the given IP address is inside the currently
+ * set network.
+ * @throws UnknownHostException
+ * */
+ public boolean contains(String ipAddr) throws UnknownHostException
+ {
+ InetAddress inetAddress1 = InetAddress.getByName(ipAddr);
+ return this.contains(inetAddress1);
+ }
+
+ /**
+ * Compares the given InetAddress against the Subnet and returns true if
+ * the ip is in the subnet-ip-range and false if not.
+ * @param inetAddress
+ * @return returns true if the given IP address is inside the currently
+ * set network.
+ * */
+ public boolean contains(InetAddress inetAddress)
+ {
+ if (cidr == null)
+ {
+ // ANY
+ return true;
+ }
+ return cidr.contains(inetAddress);
+ }
+
+ @Override
+ public String toString()
+ {
+ return cidr.toString();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof IpSubnet))
+ {
+ return false;
+ }
+ IpSubnet ipSubnet = (IpSubnet) o;
+ return ipSubnet.cidr.equals(cidr);
+ }
+
+ /**
+ * Compare two IpSubnet
+ */
+ public int compareTo(IpSubnet o)
+ {
+ return cidr.toString().compareTo(o.cidr.toString());
+ }
+
+ /**
+ * Simple test functions
+ * @param args
+ * where args[0] is the netmask (standard or CIDR notation) and optional args[1] is
+ * the inetAddress to test with this IpSubnet
+ */
+ public static void main(String[] args)
+ {
+ if (args.length != 0)
+ {
+ IpSubnet ipSubnet = null;
+ try
+ {
+ ipSubnet = new IpSubnet(args[0]);
+ }
+ catch (UnknownHostException e)
+ {
+ return;
+ }
+ System.out.println("IpSubnet: " + ipSubnet.toString() + " from " + ipSubnet.cidr.getBaseAddress() + " to "
+ + ipSubnet.cidr.getEndAddress() + " mask " + ipSubnet.cidr.getMask());
+ if (args.length > 1)
+ {
+ try
+ {
+ System.out.println("Is IN: " + args[1] + " " + ipSubnet.contains(args[1]));
+ }
+ catch (UnknownHostException e)
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSubnetFilterRule.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSubnetFilterRule.java
new file mode 100644
index 0000000000..4b27108f9b
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpSubnetFilterRule.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Ip V4 and Ip V6 filter rule.
+ *
+ * Note that mix of IPV4 and IPV6 is allowed but it is not recommended. So it is preferable to not
+ * mix IPV4 addresses with IPV6 rules, even if it should work.
+ * @author frederic bregier
+ *
+ */
+public class IpSubnetFilterRule extends IpSubnet implements IpFilterRule
+{
+ /**
+ * Is this IpV4Subnet an ALLOW or DENY rule
+ */
+ private boolean isAllowRule = true;
+
+ /**
+ * Constructor for a ALLOW or DENY ALL
+ * @param allow True for ALLOW, False for DENY
+ */
+ public IpSubnetFilterRule(boolean allow)
+ {
+ super();
+ isAllowRule = allow;
+ }
+
+ /**
+ * @param allow True for ALLOW, False for DENY
+ * @param inetAddress
+ * @param cidrNetMask
+ * @throws UnknownHostException
+ */
+ public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) throws UnknownHostException
+ {
+ super(inetAddress, cidrNetMask);
+ isAllowRule = allow;
+ }
+
+ /**
+ * @param allow True for ALLOW, False for DENY
+ * @param inetAddress
+ * @param netMask
+ * @throws UnknownHostException
+ */
+ public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) throws UnknownHostException
+ {
+ super(inetAddress, netMask);
+ isAllowRule = allow;
+ }
+
+ /**
+ * @param allow True for ALLOW, False for DENY
+ * @param netAddress
+ * @throws UnknownHostException
+ */
+ public IpSubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException
+ {
+ super(netAddress);
+ isAllowRule = allow;
+ }
+
+ public boolean isAllowRule()
+ {
+ return isAllowRule;
+ }
+
+ public boolean isDenyRule()
+ {
+ return !isAllowRule;
+ }
+
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpV4Subnet.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpV4Subnet.java
new file mode 100644
index 0000000000..8a1a322ffb
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpV4Subnet.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * This class allows to check if an IP-V4-Address is contained in a subnet.
+ * Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation)
+ * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
+ *
Example1:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example1 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ *
Example2:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example2 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+
+ * @author frederic bregier
+ *
+ */
+public class IpV4Subnet implements IpSet, Comparable
+ * i.e.:
+ * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or
+ * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0");
+ * @param netAddress a network address as string.
+ * @throws UnknownHostException
+ * */
+ public IpV4Subnet(String netAddress) throws UnknownHostException
+ {
+ setNetAddress(netAddress);
+ }
+
+ /**
+ * Create IpV4Subnet using the CIDR Notation
+ * @param inetAddress
+ * @param cidrNetMask
+ */
+ public IpV4Subnet(InetAddress inetAddress, int cidrNetMask)
+ {
+ setNetAddress(inetAddress, cidrNetMask);
+ }
+
+ /**
+ * Create IpV4Subnet using the normal Notation
+ * @param inetAddress
+ * @param netMask
+ */
+ public IpV4Subnet(InetAddress inetAddress, String netMask)
+ {
+ setNetAddress(inetAddress, netMask);
+ }
+
+ /**
+ * Sets the Network Address in either CIDR or Decimal Notation.
+ * i.e.: setNetAddress("1.1.1.1/24"); or
+ * setNetAddress("1.1.1.1/255.255.255.0");
+ * @param netAddress a network address as string.
+ * @throws UnknownHostException
+ * */
+ private void setNetAddress(String netAddress) throws UnknownHostException
+ {
+ Vector
+ * i.e.: setNetId("192.168.1.0");
+ * @param netId a network ID
+ * @throws UnknownHostException
+ * */
+ private void setNetId(String netId) throws UnknownHostException
+ {
+ InetAddress inetAddress1 = InetAddress.getByName(netId);
+ this.setNetId(inetAddress1);
+ }
+
+ /**
+ * Compute integer representation of InetAddress
+ * @param inetAddress1
+ * @return the integer representation
+ */
+ private int toInt(InetAddress inetAddress1)
+ {
+ byte[] address = inetAddress1.getAddress();
+ int net = 0;
+ for (byte addres : address)
+ {
+ net <<= 8;
+ net |= addres & BYTE_ADDRESS_MASK;
+ }
+ return net;
+ }
+
+ /**
+ * Sets the BaseAdress of the Subnet.
+ * @param inetAddress
+ * */
+ private void setNetId(InetAddress inetAddress)
+ {
+ this.inetAddress = inetAddress;
+ subnet = toInt(inetAddress);
+ }
+
+ /**
+ * Sets the Subnet's Netmask in Decimal format.
+ * i.e.: setNetMask("255.255.255.0");
+ * @param netMask a network mask
+ * */
+ private void setNetMask(String netMask)
+ {
+ StringTokenizer nm = new StringTokenizer(netMask, ".");
+ int i = 0;
+ int[] netmask = new int[4];
+ while (nm.hasMoreTokens())
+ {
+ netmask[i] = Integer.parseInt(nm.nextToken());
+ i++;
+ }
+ int mask1 = 0;
+ for (i = 0; i < 4; i++)
+ {
+ mask1 += Integer.bitCount(netmask[i]);
+ }
+ setCidrNetMask(mask1);
+ }
+
+ /**
+ * Sets the CIDR Netmask
+ * i.e.: setCidrNetMask(24);
+ * @param cidrNetMask a netmask in CIDR notation
+ * */
+ private void setCidrNetMask(int cidrNetMask)
+ {
+ cidrMask = cidrNetMask;
+ mask = SUBNET_MASK >> cidrMask - 1;
+ }
+
+ /**
+ * Compares the given IP-Address against the Subnet and returns true if
+ * the ip is in the subnet-ip-range and false if not.
+ * @param ipAddr an ipaddress
+ * @return returns true if the given IP address is inside the currently
+ * set network.
+ * @throws UnknownHostException
+ * */
+ public boolean contains(String ipAddr) throws UnknownHostException
+ {
+ InetAddress inetAddress1 = InetAddress.getByName(ipAddr);
+ return this.contains(inetAddress1);
+ }
+
+ /**
+ * Compares the given InetAddress against the Subnet and returns true if
+ * the ip is in the subnet-ip-range and false if not.
+ * @param inetAddress1
+ * @return returns true if the given IP address is inside the currently
+ * set network.
+ * */
+ public boolean contains(InetAddress inetAddress1)
+ {
+ if (mask == -1)
+ {
+ // ANY
+ return true;
+ }
+ return (toInt(inetAddress1) & mask) == subnet;
+ }
+
+ @Override
+ public String toString()
+ {
+ return inetAddress.getHostAddress() + "/" + cidrMask;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof IpV4Subnet))
+ {
+ return false;
+ }
+ IpV4Subnet ipV4Subnet = (IpV4Subnet) o;
+ return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask;
+ }
+
+ /**
+ * Compare two IpV4Subnet
+ */
+ public int compareTo(IpV4Subnet o)
+ {
+ if (o.subnet == subnet && o.cidrMask == cidrMask)
+ {
+ return 0;
+ }
+ if (o.subnet < subnet)
+ {
+ return 1;
+ }
+ else if (o.subnet > subnet)
+ {
+ return -1;
+ }
+ else if (o.cidrMask < cidrMask)
+ {
+ // greater Mask means less IpAddresses so -1
+ return -1;
+ }
+ return 1;
+ }
+
+ /**
+ * Simple test functions
+ * @param args
+ * where args[0] is the netmask (standard or CIDR notation) and optional args[1] is
+ * the inetAddress to test with this IpV4Subnet
+ */
+ public static void main(String[] args)
+ {
+ if (args.length != 0)
+ {
+ IpV4Subnet ipV4Subnet = null;
+ try
+ {
+ ipV4Subnet = new IpV4Subnet(args[0]);
+ }
+ catch (UnknownHostException e)
+ {
+ return;
+ }
+ if (args.length > 1)
+ {
+ try
+ {
+ System.out.println("Is IN: " + args[1] + " " + ipV4Subnet.contains(args[1]));
+ }
+ catch (UnknownHostException e)
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpV4SubnetFilterRule.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpV4SubnetFilterRule.java
new file mode 100644
index 0000000000..9a5c0c464e
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/IpV4SubnetFilterRule.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * IpV4 only Filter Rule
+ * @author frederic bregier
+ *
+ */
+public class IpV4SubnetFilterRule extends IpV4Subnet implements IpFilterRule
+{
+ /**
+ * Is this IpV4Subnet an ALLOW or DENY rule
+ */
+ private boolean isAllowRule = true;
+
+ /**
+ * Constructor for a ALLOW or DENY ALL
+ * @param allow True for ALLOW, False for DENY
+ */
+ public IpV4SubnetFilterRule(boolean allow)
+ {
+ super();
+ isAllowRule = allow;
+ }
+
+ /**
+ * @param allow True for ALLOW, False for DENY
+ * @param inetAddress
+ * @param cidrNetMask
+ */
+ public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask)
+ {
+ super(inetAddress, cidrNetMask);
+ isAllowRule = allow;
+ }
+
+ /**
+ * @param allow True for ALLOW, False for DENY
+ * @param inetAddress
+ * @param netMask
+ */
+ public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask)
+ {
+ super(inetAddress, netMask);
+ isAllowRule = allow;
+ }
+
+ /**
+ * @param allow True for ALLOW, False for DENY
+ * @param netAddress
+ * @throws UnknownHostException
+ */
+ public IpV4SubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException
+ {
+ super(netAddress);
+ isAllowRule = allow;
+ }
+
+ public boolean isAllowRule()
+ {
+ return isAllowRule;
+ }
+
+ public boolean isDenyRule()
+ {
+ return !isAllowRule;
+ }
+
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/OneIpFilterHandler.java b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/OneIpFilterHandler.java
new file mode 100644
index 0000000000..c984efa5a5
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/jboss/netty/handler/ipfilter/OneIpFilterHandler.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jboss.netty.handler.ipfilter;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.jboss.netty.channel.ChannelEvent;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipelineCoverage;
+import org.jboss.netty.channel.ChannelState;
+import org.jboss.netty.channel.ChannelStateEvent;
+
+/**
+ * Handler that block any new connection if there are already a currently active
+ * channel connected with the same InetAddress (IP).
+ *
+ *
+ * Take care to not change isBlocked method except if you know what you are doing
+ * since it is used to test if the current closed connection is to be removed
+ * or not from the map of currently connected channel.
+ *
+ * @author frederic bregier
+ *
+ */
+@ChannelPipelineCoverage("all")
+public class OneIpFilterHandler extends IpFilteringHandlerImpl
+{
+ /**
+ * HashMap of current remote connected InetAddress
+ */
+ private final ConcurrentMap
+ * Rule Syntax:
+ *
+ *
+ * Rule ::= [n|i]:address n stands for computer name, i for ip address
+ * address ::= <regex> | localhost
+ * regex is a regular expression with '*' as multi character and '?' as single character wild card
+ *
+ *
+ * Example: allow localhost:
+ *
+ * new PatternRule(true, "n:localhost")
+ *
+ * Example: allow local lan:
+ *
+ * new PatternRule(true, "i:192.168.0.*")
+ *
+ * Example: block all
+ *
+ * new PatternRule(false, "n:*")
+ *
+ *
+ * @author Ron
+ */
+public class PatternRule implements IpFilterRule, Comparable
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
Standard use could be as follow: The accept method must be overridden (of course you can + * override others).
+ * + *+ * {@link ChannelPipeline} pipeline = ...; + * + * IpFilterRuleHandler firewall = new IpFilterRuleHandler(); + * firewall.addAll(new IpFilterRuleList("+n:localhost, +c:192.168.0.0/27, -n:*")); + * pipeline.addFirst("firewall", firewall); + *+ * + * @apiviz.exclude ^java\.lang\. + */ +package org.jboss.netty.handler.ipfilter; + + diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/Constants.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/Constants.java new file mode 100644 index 0000000000..63dda7ba31 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/Constants.java @@ -0,0 +1,38 @@ +package org.rzo.netty.ahessian; + +import org.jboss.netty.logging.InternalLogger; +import org.jboss.netty.logging.InternalLoggerFactory; + +public interface Constants +{ + public static final String HEADER_STRING = "H"; + public static final Integer GROUP_HEADER_KEY = 0; + public static final Integer CALL_ID_HEADER_KEY = 1; + public static final Integer SERVICE_ID_HEADER_KEY = 2; + + public static final Integer CALLBACK_ID_HEADER_KEY = 3; + public static final Integer CALLBACK_METHOD_HEADER_KEY = 4; + public static final Integer CALLBACK_ARGS_HEADER_KEY = 5; + public static final Integer CALLBACK_DONE_HEADER_KEY = 6; + + public static final Integer COMPLETED_HEADER_KEY = 7; + public static final Integer HAS_SESSION_FILTER_HEADER_KEY = 8; + + public static final int IGROUP_HEADER_KEY = 0; + public static final int ICALL_ID_HEADER_KEY = 1; + public static final int ISERVICE_ID_HEADER_KEY = 2; + + public static final int ICALLBACK_ID_HEADER_KEY = 3; + public static final int ICALLBACK_METHOD_HEADER_KEY = 4; + public static final int ICALLBACK_ARGS_HEADER_KEY = 5; + public static final int ICALLBACK_DONE_HEADER_KEY = 6; + + public static final int ICOMPLETED_HEADER_KEY = 7; + public static final int IHAS_SESSION_FILTER_HEADER_KEY = 8; + + + public static final InternalLogger ahessianLogger = + InternalLoggerFactory.getInstance("ahessian"); + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/application/file/remote/server/AsyncFileServiceImpl.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/application/file/remote/server/AsyncFileServiceImpl.java new file mode 100644 index 0000000000..2d6f3eab5d --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/application/file/remote/server/AsyncFileServiceImpl.java @@ -0,0 +1,36 @@ +package org.rzo.netty.ahessian.application.file.remote.server; + +import java.io.File; +import java.io.InputStream; +import java.util.List; + +import org.rzo.netty.ahessian.application.file.remote.service.AsyncFileService; +import org.rzo.netty.ahessian.application.file.remote.service.FileObject; + +public class AsyncFileServiceImpl implements AsyncFileService +{ + + public FileObject getFile(String file) + { + File f = new File(file); + if (!f.exists()) + return null; + return toFileObject(f); + } + + private FileObject toFileObject(File f) + { + return new FileObjectImpl(f); + } + + public InputStream getInputStream(String file) + { + return null; + } + + public List
createMBean(className, objectName, null, null)
.
+ *
+ * @see #createMBean(String, ObjectName, Object[], String[])
+ */
+ public Object createMBean(String className, ObjectName objectName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, IOException;
+
+ /**
+ * Instantiates and registers an MBean of the specified class with the given ObjectName in the MBeanServer.
+ * The MBeanServer will use its ClassLoaderRepository to load the class of the MBean and the specified
+ * constructor's parameter classes, and creates the instance passing the specified arguments.
+ * The ObjectName may be null if the MBean implements {@link MBeanRegistration}
+ *
+ * @param className The class name of the MBean to be instantiated.
+ * @param objectName The ObjectName of the MBean, may be null.
+ * @param args An array containing the arguments to pass to the constructor.
+ * @param parameters An array containing the signature of the constructor.
+ * @return An ObjectInstance, containing the ObjectName and the Java class name of the newly instantiated MBean.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws InstanceAlreadyExistsException If another MBean with the same ObjectName is already registered in the MBeanServer.
+ * @throws MBeanRegistrationException If an exception is thrown during MBean's registration.
+ * @throws MBeanException If the constructor of the MBean has thrown an exception
+ * @throws NotCompliantMBeanException If the MBean is not a JMX compliant MBean
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object createMBean(String className, ObjectName objectName, Object[] args, String[] parameters)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, IOException;
+
+ /**
+ * A facility method for createMBean(className, objectName, loaderName, null, null)
.
+ *
+ * @see #createMBean(String, ObjectName, ObjectName, Object[], String[])
+ */
+ public Object createMBean(String className, ObjectName objectName, ObjectName loaderName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException, IOException;
+
+ /**
+ * Instantiates and registers an MBean of the specified class with the given ObjectName in the MBeanServer.
+ * The MBeanServer will use the specified classloader MBean to load the class of the MBean and the specified
+ * constructor's parameter classes, and creates the instance passing the specified arguments, or the classloader
+ * of the MBeanServer if the classloader ObjectName is null.
+ * The ObjectName may be null if the MBean implements {@link MBeanRegistration}
+ *
+ * @param className The class name of the MBean to be instantiated.
+ * @param objectName The ObjectName of the MBean, may be null.
+ * @param loaderName The ObjectName of the classloader MBean to be used.
+ * @param args An array containing the arguments to pass to the constructor.
+ * @param parameters An array containing the signature of the constructor.
+ * @return An ObjectInstance, containing the ObjectName and the Java class name of the newly instantiated MBean.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws InstanceAlreadyExistsException If another MBean with the same ObjectName is already registered in the MBeanServer.
+ * @throws MBeanRegistrationException If an exception is thrown during MBean's registration.
+ * @throws MBeanException If the constructor of the MBean has thrown an exception
+ * @throws NotCompliantMBeanException If the MBean is not a JMX compliant MBean
+ * @throws InstanceNotFoundException If the specified classloader MBean is not registered in the MBeanServer.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object createMBean(String className, ObjectName objectName, ObjectName loaderName, Object[] args, String[] parameters)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException, IOException;
+
+ /**
+ * Unregisters the MBean with the specified ObjectName from this MBeanServer.
+ *
+ * @param objectName The ObjectName of the MBean to be unregistered.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws MBeanRegistrationException If an exception is thrown during MBean's unregistration.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object unregisterMBean(ObjectName objectName)
+ throws InstanceNotFoundException, MBeanRegistrationException, IOException;
+
+ /**
+ * Gets the value of the specified attribute of the named MBean.
+ *
+ * @param objectName The ObjectName of the MBean from which the attribute is to be retrieved.
+ * @param attribute The attribute name.
+ * @return The value of the specified attribute.
+ * @throws AttributeNotFoundException If the specified attribute does not belong to the management interface of the MBean.
+ * @throws MBeanException If the MBean's getter method throws an exception.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws IOException If a communication problem occurred.
+ * @see #setAttribute
+ */
+ public Object getAttribute(ObjectName objectName, String attribute)
+ throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException;
+
+ /**
+ * Sets the value of the specified attribute of the named MBean.
+ *
+ * @param objectName The name of the MBean within which the attribute is to be set.
+ * @param attribute The Attribute to be set.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws AttributeNotFoundException If the specified attribute does not belong to the management interface of the MBean.
+ * @throws InvalidAttributeValueException If the value specified for the attribute does not match the attribute's type
+ * @throws MBeanException If the MBean's setter method throws an exception.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws IOException If a communication problem occurred.
+ * @see #getAttribute
+ */
+ public Object setAttribute(ObjectName objectName, Attribute attribute)
+ throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException, IOException;
+
+ /**
+ * Gets the values of several attributes of the named MBean.
+ *
+ * @param objectName The ObjectName of the MBean from which the attributes are to be retrieved.
+ * @param attributes The attribute names.
+ * @return An AttributeList containing the values of the attributes that it has been possible to retrieve.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws IOException If a communication problem occurred.
+ * @see #setAttributes
+ */
+ public Object getAttributes(ObjectName objectName, String[] attributes)
+ throws InstanceNotFoundException, ReflectionException, IOException;
+
+ /**
+ * Sets the values of several attributes of the named MBean.
+ *
+ * @param objectName The name of the MBean within which the attribute is to be set.
+ * @param attributes The AttributeList containing the Attributes to be set.
+ * @return The AttributeList containing the attributes that it has been possible to set.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws IOException If a communication problem occurred.
+ * @see #getAttributes
+ */
+ public Object setAttributes(ObjectName objectName, AttributeList attributes)
+ throws InstanceNotFoundException, ReflectionException, IOException;
+
+ /**
+ * Invokes the specified operation on the named MBean.
+ *
+ * @param objectName The ObjectName of the MBean on which the method is to be invoked.
+ * @param methodName The name of the operation to be invoked.
+ * @param args An array containing the arguments to pass to the operation.
+ * @param parameters An array containing the signature of the operation.
+ * @return The return value of the operation, or null if the operation returns void.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws MBeanException If the MBean's operation method throws an exception.
+ * @throws ReflectionException If a reflection exception is thrown.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object invoke(ObjectName objectName, String methodName, Object[] args, String[] parameters)
+ throws InstanceNotFoundException, MBeanException, ReflectionException, IOException;
+
+ /**
+ * Returns the number of MBeans registered in this MBeanServer.
+ *
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object getMBeanCount()
+ throws IOException;
+
+ /**
+ * Checks whether the given ObjectName identifies an MBean registered in this MBeanServer.
+ *
+ * @param objectName The ObjectName to be checked.
+ * @return True if an MBean with the specified ObjectName is already registered in the MBeanServer.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object isRegistered(ObjectName objectName)
+ throws IOException;
+
+ /**
+ * Gets the ObjectInstance for the named MBean registered with the MBeanServer.
+ *
+ * @param objectName The ObjectName of the MBean.
+ * @return The ObjectInstance associated with the named MBean.
+ * @throws InstanceNotFoundException If the specified MBean is not registered in the MBeanServer.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object getObjectInstance(ObjectName objectName)
+ throws InstanceNotFoundException, IOException;
+
+ /**
+ * Gets a subset of the ObjectInstances belonging to MBeans registered in this MBeanServer.
+ * It is possible to filter the set of MBeans by specifying a pattern for MBean's ObjectNames, and a query expression
+ * to be evaluated to further filter the set of MBeans.
+ * The set can be further restricted if any exception is thrown during retrieval of MBean (for example for
+ * security reasons): the failing MBean will not be included.
+ *
+ * @param patternName The ObjectName pattern identifying the MBeans to be retrieved, or null to retrieve all MBeans.
+ * @param filter The query expression to be evaluated for selecting MBeans, or null.
+ * @return A set containing the ObjectInstance objects for the selected MBeans.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object queryMBeans(ObjectName patternName, QueryExp filter)
+ throws IOException;
+
+ /**
+ * Gets a subset of the ObjectNames belonging to MBeans registered in this MBeanServer.
+ * It is possible to filter the set of MBeans by specifying a pattern for MBean's ObjectNames, and a query expression
+ * to be evaluated to further filter the set of MBeans.
+ * The set can be further restricted if any exception is thrown during retrieval of MBean (for example for
+ * security reasons): the failing MBean will not be included.
+ *
+ * @param patternName The ObjectName pattern identifying the MBeans to be retrieved, or null to retrieve all MBeans.
+ * @param filter The query expression to be evaluated for selecting MBeans, or null.
+ * @return A set containing the ObjectNames for the selected MBeans.
+ * @throws IOException If a communication problem occurred.
+ */
+ public Object queryNames(ObjectName patternName, QueryExp filter)
+ throws IOException;
+}
diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/application/jmx/remote/service/JmxSerializerFactory.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/application/jmx/remote/service/JmxSerializerFactory.java
new file mode 100644
index 0000000000..b847a154b2
--- /dev/null
+++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/application/jmx/remote/service/JmxSerializerFactory.java
@@ -0,0 +1,30 @@
+package org.rzo.netty.ahessian.application.jmx.remote.service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.ObjectName;
+
+import org.rzo.netty.ahessian.rpc.message.MappingSerializerFactory;
+
+import com.caucho.hessian4.io.ObjectNameDeserializer;
+import com.caucho.hessian4.io.StringValueSerializer;
+
+public class JmxSerializerFactory extends MappingSerializerFactory
+{
+ static Map+ * {@link ChannelPipeline} pipeline = ...; + * + * EncryptedAuthToken token = new EncryptedAuthToken(); + * token.setAlgorithm("SHA-1"); + * token.setPassword("test"); + * ClientAuthFilter auth = new ClientAuthFilter(token); + * pipeline.addLast("auth", auth); + *+ * + */ +@ChannelPipelineCoverage("one") +public class ClientAuthFilter extends SimpleChannelUpstreamHandler +{ + + /** The authentication token. */ + AuthToken _token; + + /** + * Instantiates a new client authentication handler. + * + * @param token the token + */ + public ClientAuthFilter(AuthToken token) + { + _token = token; + } + + /* (non-Javadoc) + * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent) + */ + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + _token.sendPassword(ctx); + ctx.sendUpstream(e); + } + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/EncryptedAuthToken.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/EncryptedAuthToken.java new file mode 100644 index 0000000000..576739a902 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/EncryptedAuthToken.java @@ -0,0 +1,42 @@ +package org.rzo.netty.ahessian.auth; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * An Encrypted Authentication Token. + * The password is transmitted encrypted. + */ +public class EncryptedAuthToken extends SimpleAuthToken +{ + + /** The _algorithm. */ + MessageDigest _algorithm = null; + + /** + * Sets the algorithm. + * + * @param algorithm the encryption algorithm. + * @see java.security.MessageDigest + * + * @throws NoSuchAlgorithmException + */ + public void setAlgorithm(String algorithm) throws NoSuchAlgorithmException + { + _algorithm = MessageDigest.getInstance(algorithm); + + } + + /* (non-Javadoc) + * @see org.rzo.netty.ahessian.auth.SimpleAuthToken#setPassword(java.lang.String) + */ + public void setPassword(String password) + { + _algorithm.reset(); + _algorithm.update(password.getBytes()); + _password = ensureLength(_algorithm.digest()); + _receivedBytes = new byte[_password.length]; + + } + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/ServerAuthFilter.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/ServerAuthFilter.java new file mode 100644 index 0000000000..fb50585767 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/ServerAuthFilter.java @@ -0,0 +1,91 @@ +package org.rzo.netty.ahessian.auth; + +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineCoverage; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.logging.InternalLogger; +import org.jboss.netty.logging.InternalLoggerFactory; + +/** + * Server side authentication handler. + *
+ * {@link ChannelPipeline} pipeline = ...; + * + * EncryptedAuthToken token = new EncryptedAuthToken(); + * token.setAlgorithm("SHA-1"); + * token.setPassword("test"); + * ServerAuthFilter auth = new ServerAuthFilter(token); + * pipeline.addLast("auth", auth); + *+ * + */ +@ChannelPipelineCoverage("one") +public class ServerAuthFilter extends SimpleChannelUpstreamHandler +{ + private AuthToken _token = null; + private boolean _authenticated = false; + private static final InternalLogger logger = + InternalLoggerFactory.getInstance(ServerAuthFilter.class); + + /** + * Instantiates a new server auth filter. + * + * @param token the token + */ + public ServerAuthFilter(AuthToken token) + { + setToken(token); + } + + /** + * Sets the token. + * + * @param token the new token + */ + public void setToken(AuthToken token) + { + _token = token; + } + + /* (non-Javadoc) + * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent) + */ + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception + { + if (!_authenticated) + { + int result = _token.authenticate(ctx, e); + if ( result == AuthToken.FAILED) + { + logger.warn("authentication failed -> close connection"); + ctx.getChannel().close(); + } + else if (result == AuthToken.PASSED) + { + _authenticated = true; + } + } + else + ctx.sendUpstream(e); + } + + @Override + public void channelDisconnected( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception + { + _token.disconnected(); + ctx.sendUpstream(e); + } + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/SimpleAuthToken.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/SimpleAuthToken.java new file mode 100644 index 0000000000..c18e5866ef --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/auth/SimpleAuthToken.java @@ -0,0 +1,119 @@ +package org.rzo.netty.ahessian.auth; + +import java.util.Arrays; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.logging.InternalLogger; +import org.jboss.netty.logging.InternalLoggerFactory; + +/** + * A Simple Authentication Token. + * The password is sent unencrypted. + */ +public class SimpleAuthToken implements AuthToken +{ + + /** The _password. */ + byte[] _password; + + /** The _received bytes. */ + byte[] _receivedBytes; + + /** The _received length. */ + int _receivedLength = 0; + + boolean _loggedOn = false; + + int _length = -1; + + private static final InternalLogger logger = + InternalLoggerFactory.getInstance(SimpleAuthToken.class); + + + /** + * Sets the password. + * + * @param password the new password + */ + public void setPassword(String password) + { + _password = ensureLength(password.getBytes()); + _receivedBytes = new byte[_password.length]; + } + + public void setLength(int length) + { + _length = length; + } + + /* (non-Javadoc) + * @see org.rzo.netty.ahessian.auth.AuthToken#authenticate(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent) + */ + public int authenticate(ChannelHandlerContext ctx, MessageEvent e) + { + ChannelBuffer b = (ChannelBuffer) e.getMessage(); + int toCopy = Math.min(_receivedBytes.length-_receivedLength, b.readableBytes()); + byte[] bytes = new byte[toCopy]; + b.readBytes(bytes); + System.arraycopy(bytes, 0, _receivedBytes, _receivedLength, bytes.length); + _receivedLength += toCopy; + if (_receivedLength == _password.length) + { + if (Arrays.equals(_receivedBytes, _password)) + { + logger.info("authenticated"); + if (b.readableBytes() != 0) + ctx.sendUpstream(e); + return PASSED; + } + else + return FAILED; + } + else + return NOT_COMPLETE; + } + + /* (non-Javadoc) + * @see org.rzo.netty.ahessian.auth.AuthToken#sendPassword(org.jboss.netty.channel.ChannelHandlerContext) + */ + public void sendPassword(ChannelHandlerContext ctx) + { + Channels.write(ctx, Channels.future(ctx.getChannel()), ChannelBuffers.wrappedBuffer(_password)); + } + + public boolean isLoggedOn() + { + return _loggedOn; + } + + void setLoggedOn(boolean loggedOn) + { + _loggedOn = loggedOn; + } + + public void disconnected() + { + setLoggedOn(false); + } + + byte[] ensureLength(byte[] bytes) + { + if (bytes.length == _length || _length <= 0) + return bytes; + else + { + return Arrays.copyOf(bytes, _length); + } + } + + byte[] getPassword() + { + return _password; + } + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/ClientCryptoFilter.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/ClientCryptoFilter.java new file mode 100644 index 0000000000..cbe12e4dfb --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/ClientCryptoFilter.java @@ -0,0 +1,221 @@ +package org.rzo.netty.ahessian.crypto; + +import java.io.ByteArrayOutputStream; +import java.security.Key; +import java.security.KeyFactory; +import java.security.SecureRandom; +import java.security.spec.KeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +import javax.crypto.Cipher; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelEvent; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; +import org.rzo.netty.ahessian.log.OutLogger; + +public class ClientCryptoFilter extends SimpleChannelHandler implements CryptoConstants +{ + private StreamCipher _encodeCipher; + private StreamCipher _decodeCipher; + private byte[] _encodedPublicKey; + private int _bytesRead; + private SecureRandom _secureRandom = new SecureRandom(); + private ChannelEvent _connectedEvent; + private byte[] _password = new byte[PASSWORD_SIZE]; + + public ClientCryptoFilter() + { + super(); + Arrays.fill(_password, (byte)0); + } + + + + + public void messageReceived( + ChannelHandlerContext ctx, MessageEvent e) throws Exception + { + // have we sent our secret key ? + if (_decodeCipher != null) + { + // decode and send upstream + MessageEvent m = Util.code(_decodeCipher, e, true); + ctx.sendUpstream(m); + } + // we are still in the crypto protocol + else + { + ChannelBuffer b = (ChannelBuffer) e.getMessage(); + // is this our first message ? + if (_encodedPublicKey == null) + { + int size = b.readInt(); + _encodedPublicKey = new byte[size]; + } + // readin the server's public key + // it may come in multiple chunks + int available = b.readableBytes(); + int toRead = Math.min(_encodedPublicKey.length - _bytesRead, available); + b.readBytes(_encodedPublicKey, _bytesRead, toRead); + _bytesRead += toRead; + // we have completed reception of the public key ? + if (_bytesRead == _encodedPublicKey.length) + { + // generate our secret key and send it to the server + sendSecretKey(ctx); + } + } + } + + private Cipher getAsymCipher() + { + try + { + // generate Cipher using the server's public key + KeyFactory fact = KeyFactory.getInstance(ASYM_KEY_TYPE); + KeySpec ks = new X509EncodedKeySpec(_encodedPublicKey); + Key pubKey = fact.generatePublic(ks); + String type = "".equals(ASYM_CIPHER_TYPE) ? ASYM_KEY_TYPE : ASYM_KEY_TYPE+"/"+ASYM_CIPHER_TYPE; + Cipher result = Cipher.getInstance(type); + result.init(Cipher.ENCRYPT_MODE, pubKey); + return result; + } + catch (Exception ex) + { + ex.printStackTrace(); + } + return null; + } + + private byte[] getSymKey() + //private Key getSymKey() + { + // generate a random secret key + try + { +// KeyGenerator keyGenerator = KeyGenerator.getInstance(SYM_KEY_TYPE); +// keyGenerator.init(SYM_KEY_SIZE); +// return keyGenerator.generateKey(); + byte[] key = new byte[SYM_KEY_SIZE]; + _secureRandom.nextBytes(key); + return key; + + } + catch (Exception ex) + { + ex.printStackTrace(); + } + return null; + } + + private byte[] getIv() + { + byte[] iv = new byte[SYM_IV_SIZE]; + _secureRandom.nextBytes(iv); + return iv; + } + + private void sendSecretKey(ChannelHandlerContext ctx) + { + try + { + // generate our secret key and iv and write it to a buffer + byte[] symKeyEncoded = getSymKey(); + byte[] ivEncoded = getIv(); + ByteArrayOutputStream b = new ByteArrayOutputStream(); + b.write(ivEncoded); + b.write(symKeyEncoded); + if (_password != null) + b.write(_password); + b.flush(); + + System.out.println("generated iv+key: "+OutLogger.asString(b.toByteArray())); + + // encode it using the server's public key + Cipher asymCipher = getAsymCipher(); + byte[] encryptedIvSymKey = asymCipher.doFinal(b.toByteArray()); + ChannelBuffer cb = ChannelBuffers.dynamicBuffer(); + cb.writeInt(encryptedIvSymKey.length); + cb.writeBytes(encryptedIvSymKey); + + // send it to the server + Channel channel = ctx.getChannel(); + ChannelFuture future = Channels.future(ctx.getChannel()); + + Channels.write(ctx, future, cb); + + // wait for the message transmission + future.await(); + + // we can now accept in/out messages encrypted with our key + // first create symmetric ciphers + _encodeCipher = StreamCipherFactory.createCipher(SYM_KEY_TYPE); + _encodeCipher.engineInitEncrypt(symKeyEncoded, ivEncoded); + + _decodeCipher = StreamCipherFactory.createCipher(SYM_KEY_TYPE); + _decodeCipher.engineInitDecrypt(symKeyEncoded, ivEncoded); + + // inform others in the pipeline that a secure connection has been established + ctx.sendUpstream(_connectedEvent); + + } + catch (Exception ex) + { + ex.printStackTrace(); + } + + } + + + + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + // remember this event, so that we can propagate it to the rest of the pipeline once we have + // encryption and decryption ciphers in place + _connectedEvent = e; + } + + @Override + public void writeRequested( + ChannelHandlerContext ctx, MessageEvent e) throws Exception + { + // if we can encode + if (_encodeCipher != null) + { + // encode the message and send it downstream + MessageEvent m = Util.code(_encodeCipher, e, false); + ctx.sendDownstream(m); + } + // else ignore. this should not happen, since we have not yet propagated the connected event. + + } + + public void setPassword(byte[] password) + { + if (password == null || password.length == 0) + return; + int length = Math.min(PASSWORD_SIZE, password.length); + System.arraycopy(password, 0, _password, 0, length); + } + + + + public static void main(String[] args) + { + ServerCryptoFilter s = new ServerCryptoFilter(); + ClientCryptoFilter c = new ClientCryptoFilter(); + c._encodedPublicKey = s.getPublicKeyEncoded(); + c.sendSecretKey(null); + } + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/CryptoConstants.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/CryptoConstants.java new file mode 100644 index 0000000000..003761e95c --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/CryptoConstants.java @@ -0,0 +1,21 @@ +package org.rzo.netty.ahessian.crypto; + +public interface CryptoConstants +{ + public static String ASYM_KEY_TYPE = "RSA"; + public static String ASYM_CIPHER_TYPE = "ECB/NOPADDING"; + public static String SYM_KEY_TYPE = "RC4";//"Salsa20";//"RC4";// + // if lower than 512 java throws an exception + // size in bits + public static int ASYM_KEY_SIZE = 512; + // size in bytes + public static int SYM_KEY_SIZE = 16; + // only required for salsa20, must be 8 byte + // size in bytes + public static int SYM_IV_SIZE = 8; + + // size of password in bytes + // password is used to avoid MITM attacks + public static int PASSWORD_SIZE = 15; + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/CryptoException.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/CryptoException.java new file mode 100644 index 0000000000..e25e20c436 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/CryptoException.java @@ -0,0 +1,27 @@ +package org.rzo.netty.ahessian.crypto; + +/** + * This class is for any unexpected exception in the crypto library. + *
+ * Copyright © 1997
+ * Systemics Ltd on behalf of the
+ * Cryptix Development Team.
+ *
All rights reserved.
+ *
+ * $Revision: 1.6 $ + * @author David Hopwood + * @since Cryptix 2.2.2 + */ + + + public class CryptoException extends Exception { + public CryptoException() { + super (); + } + + /** @param reason the reason why the exception was thrown. */ + public CryptoException(String reason) { + super(reason); + } + } + diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/RC4Cipher.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/RC4Cipher.java new file mode 100644 index 0000000000..808dba21b2 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/crypto/RC4Cipher.java @@ -0,0 +1,334 @@ +package org.rzo.netty.ahessian.crypto; + +import java.util.Arrays; + +/** + * Taken from the cryptix project + * This class implements the RC4 (TM) stream cipher. + *
+ * The source code (C version) from which this port was done, is the one + * posted to the sci.crypt, alt.security, comp.security.misc, and + * alt.privacy newsgroups on Wed, 14 Sep 1994 06:35:31 GMT by + * "David Sterndark" <sterndark@netcom.com> + * (Message-ID: <sternCvKL4B.Hyy@netcom.com>) + *
+ * RC4 (TM) was designed by Ron Rivest, and was previously a trade secret of + * RSA Data Security, Inc. The algorithm is now in the public domain. The name + * "RC4" is a trademark of RSA Data Security, Inc. + *
+ * References: + *
+ * Copyright © 1997
+ * Systemics Ltd on behalf of the
+ * Cryptix Development Team.
+ *
All rights reserved.
+ *
+ * $Revision: 1.6 $
+ * @author Raif S. Naffah
+ * @author David Hopwood
+ * @since Cryptix 2.2.2
+ */
+
+
+public class RC4Cipher implements StreamCipher
+{
+ // RC4 constants and variables
+ //............................................................................
+
+ /**
+ * The state of the cipher object when it is uninitialized,
+ * that is, the state it is in right after it has been created.
+ */
+ public static final int UNINITIALIZED = 0;
+
+ /**
+ * The state of the cipher when it is ready to encrypt, that is,
+ * the state it is in right after a call to initEncrypt
.
+ *
+ * @see #initEncrypt
+ */
+ public static final int ENCRYPT = 1;
+
+ /**
+ * The state of the cipher when it is ready to decrypt, that is,
+ * the state it is in right after a call to initDecrypt
.
+ *
+ * @see #initDecrypt
+ */
+ public static final int DECRYPT = 2;
+
+ /**
+ * Will hold the contents of the current set S-box.
+ */
+ private int[] sBox = new int[256];
+
+ /**
+ * The two indices for the S-box computation referred to as i and j
+ * in Schneier.
+ */
+ private int x, y;
+
+ /**
+ * The block size of this cipher. Being a stream cipher this value
+ * is 1!
+ */
+ private static final int BLOCK_SIZE = 1;
+
+ private int state; // defaults to UNINITIALIZED = 0
+ private String cipherName = "RC4";
+
+ // Constructor, finalizer, and clone()
+ //............................................................................
+
+ /**
+ * Constructs an RC4 cipher object, in the UNINITIALIZED state.
+ * This calls the Cipher constructor with implBuffering false,
+ * implPadding false and the provider set to "Cryptix".
+ */
+ public RC4Cipher() {
+ //super(false, false, "Cryptix");
+ }
+
+ /**
+ * Always throws a CloneNotSupportedException (cloning of ciphers is not
+ * supported for security reasons).
+ */
+ public final Object clone() throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+ // Implementation of JCE methods
+ //............................................................................
+
+ /**
+ * SPI: Returns the length of an input block, in bytes.
+ *
+ * @return the length in bytes of an input block for this cipher.
+ */
+ public int engineBlockSize() {
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * SPI: Initializes this cipher for encryption, using the
+ * specified key.
+ *
+ * @param key the key to use for encryption.
+ * @exception CryptoException if the key is invalid.
+ */
+ public void engineInitEncrypt(byte[] key, byte[] iv) throws CryptoException {
+ makeKey(key);
+ state = ENCRYPT;
+ }
+
+ /**
+ * SPI: Initializes this cipher for decryption, using the
+ * specified key.
+ *
+ * @param key the key to use for decryption.
+ * @exception CryptoException if the key is invalid.
+ */
+ public void engineInitDecrypt(byte[] key, byte[] iv) throws CryptoException {
+ makeKey(key);
+ state = ENCRYPT;
+ }
+
+ /**
+ * SPI: This is the main engine method for updating data.
+ *
+ * in and out may be the same array, and the input and output + * regions may overlap. + * + * @param in the input data. + * @param inOffset the offset into in specifying where the data starts. + * @param inLen the length of the subarray. + * @param out the output array. + * @param outOffset the offset indicating where to start writing into + * the out array. + * @return the number of bytes written. + * reports an error. + */ + protected int engineUpdate(byte[] in, int inOffset, int inLen, + byte[] out, int outOffset) { + if (inLen < 0) + throw new IllegalArgumentException("inLen < 0"); + + boolean doEncrypt = (getState() == ENCRYPT); + + // Avoid overlapping input and output regions. + if (in == out + && (outOffset >= inOffset + && outOffset < inOffset + inLen || inOffset >= outOffset + && inOffset < outOffset + inLen)) { + byte[] newin = new byte[inLen]; + System.arraycopy(in, inOffset, newin, 0, inLen); + in = newin; + inOffset = 0; + } + + rc4(in, inOffset, inLen, out, outOffset); + + return inLen; + } + + // Own methods + //............................................................................ + + /** + * RC4 encryption/decryption. The input and output regions are assumed not to + * overlap. + * + * @param in the input data. + * @param inOffset the offset into in specifying where the data starts. + * @param inLen the length of the subarray. + * @param out the output array. + * @param outOffset the offset indicating where to start writing into + * the out array. + */ + private void rc4(byte[] in, int inOffset, int inLen, byte[] out, + int outOffset) { + int xorIndex, t; + + for (int i = 0; i < inLen; i++) { + x = (x + 1) & 0xFF; + y = (sBox[x] + y) & 0xFF; + + t = sBox[x]; + sBox[x] = sBox[y]; + sBox[y] = t; + + xorIndex = (sBox[x] + sBox[y]) & 0xFF; + out[outOffset++] = (byte) (in[inOffset++] ^ sBox[xorIndex]); + } + } + + /** + * Expands a user-key to a working key schedule. + *
+ * The key bytes are first extracted from the user-key and then + * used to build the contents of this key schedule. + *
+ * The method's only exceptions are when the user-key's contents + * are null, or a byte array of zero length. + * + * @param key the user-key object to use. + * @exception CryptoException if one of the following occurs:
+ * See + * International JCE Standard Algorithm Names for a list + * of Cipher algorithm names. + * + * @return the standard cipher name (such as "DES"). + */ + public final String getAlgorithm() { + return cipherName; + } + + /** + * Returns the state of this Cipher object. Possible states are: + *
+ *
+ * {@link ChannelPipeline} pipeline = ...; + * + * // Encoder + * pipeline.addLast("outputStream", new {@link handler.io.OutputStream}()); + * pipeline.addLast("outputHandler", new MyOutputHandler()); + * + * // Decoder + * pipeline.addLast("inputStream", new {@link handler.io.InputStream}()); + * pipeline.addLast("inputHandler", new MyInputHandler()); + *+ * + * and then, within the handler you can use a {@link java.io.InputStream} or + * {@link java.io.OutputStream} instead of a {@link ChannelBuffer} as a message:
+ * // synchronized for multithreaded environment to avoid messages mixing + * synchronized public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception + * { + * byte[] message = (byte[]) e.getMessage(); + * OutputStream out = OutputStreamEncoder.getOutputStream(ctx); + * out.write(message); + * // if this is the last chunk of bytes we should flush the output + * out.flush(); + * // netty seems to require this, so that the boss thread may read input from the channel + * Thread.yield(); + * } + * + *+ * + *
+ * void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + * { + * // message received is called only once to deliver the input stream + * // it is called in a separate thread and not in the netty worker thread. + * // incoming bytes are consumed in this method. + * // the stream is closed once the channel is disconnected + * InputStream in = (InputStream) evt.getMessage(); + * + * while (ctx.getChannel().isConnected()) + * { + * // parse the incoming stream and forward the result to the next handler + * Channels.fireMessageReceived(ctx, parseReply(in)); + * } + * } + *+ */ +public class InputStreamDecoder extends SimpleChannelUpstreamHandler implements StopableHandler +{ + + /** Thread pool for getting a thread for calling the next handler */ + InputStreamBuffer _in = null; + boolean _stopEnabled = true; + boolean _crcCheck = false; + + public InputStreamDecoder() + { + + } + + public InputStreamDecoder (boolean crcCheck) + { + _crcCheck = crcCheck; + } + + /** + * Instantiates a new input stream decoder. + * + * @param executor + * the thread pool + */ + /* + * (non-Javadoc) + * + * @see + * org.jboss.netty.channel.SimpleChannelUpstreamHandler#messageReceived( + * org.jboss.netty.channel.ChannelHandlerContext, + * org.jboss.netty.channel.MessageEvent) + */ + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception + { + _in.write((ChannelBuffer) e.getMessage()); + + fireMessageReceived(ctx, _in, e.getRemoteAddress()); + } + + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception + { + if (_in == null) + { + if (_crcCheck) + _in = new CRCInputStream(); + else + _in = new InputStreamBuffer(); + ctx.setAttachment(_in); + } + ctx.sendUpstream(e); + } + + public static InputStreamBuffer getInputStream(ChannelHandlerContext ctx) + { + return (InputStreamBuffer) ctx.getPipeline().getContext(InputStreamDecoder.class).getAttachment(); + } + + public boolean isStopEnabled() + { + return _stopEnabled; + } + + public void setStopEnabled(boolean stopEnabled) + { + _stopEnabled = stopEnabled; + } + + public void stop() + { + try + { + _in.close(); + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + _in = null; + } + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/OutputStreamBuffer.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/OutputStreamBuffer.java new file mode 100644 index 0000000000..a590ad838d --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/OutputStreamBuffer.java @@ -0,0 +1,188 @@ +package org.rzo.netty.ahessian.io; + +import static org.jboss.netty.buffer.ChannelBuffers.dynamicBuffer; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.DownstreamMessageEvent; +import org.rzo.netty.ahessian.Constants; +import org.rzo.netty.ahessian.utils.MyReentrantLock; + +import com.caucho.hessian4.io.FlushableOutput; + +/** + * A buffer for storing outgoing bytes. Bytes are sent upstream if + * The number of written bytes is > than a watermark, or if flush is called + */ +public class OutputStreamBuffer extends OutputStream implements FlushableOutput +{ + + /** The context of the channel on which to send the bytes downstream */ + private volatile ChannelHandlerContext _ctx; + + /** Indicates if the stream has been closed */ + private volatile boolean _closed = false; + private Lock _lock = new MyReentrantLock(); + + /** If written bytes > watermark, the bytes are sent downstream */ + int _watermark = 1024*1024; + int _initialBuffSize = 1024; + + /** The buffer for storing outgoing bytes. Once the bytes have been sent downstream a new buffer is created */ + private ChannelBuffer _buf = dynamicBuffer(_initialBuffSize); + + + /** + * Instantiates a new output stream buffer. + * + * @param ctx the context in which bytes are sent downstream + */ + OutputStreamBuffer(ChannelHandlerContext ctx) + { + super(); + _ctx = ctx; + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(int) + */ + @Override + public void write(int b) throws IOException + { + if (_closed) + throw new IOException("stream closed"); + _lock.lock(); + try + { + //System.out.println("write "+_buf.readableBytes()); + _buf.writeByte((byte)b); + if (_buf.writerIndex() >= _watermark) + sendDownstream(null); + } + finally + { + _lock.unlock(); + } + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(byte[], int, int) + */ + @Override + public void write(byte b[], int off, int len) throws IOException + { + if (_closed) + throw new IOException("stream closed"); + _lock.lock(); + try + { + _buf.writeBytes(b, off, len); + //System.out.println("write "+len+" "+_buf.readableBytes()); + if (_buf.writerIndex() >= _watermark) + sendDownstream(null); + } + finally + { + _lock.unlock(); + } + + } + + /* (non-Javadoc) + * @see java.io.OutputStream#flush() + */ + @Override + public void flush() throws IOException + { + flush(null); + } + + + public void flush(ChannelFuture future) throws IOException + { + _lock.lock(); + if (_buf.readableBytes() > 0) + try + { + super.flush(); + if (future == null) + { + ChannelFuture f = sendDownstream(null); + f.await(20000); + //if (!f.await(10000)) + // throw new IOException("write longer than 10 secs"); + } + else + { + sendDownstream(future); + } + } + catch (Exception e) + { + throw new IOException(e); + } + finally + { + _lock.unlock(); + } + } + + private ChannelFuture sendDownstream(ChannelFuture future) throws IOException + { + if (! _ctx.getChannel().isConnected()) + throw new IOException("channel disconnected"); + while (!_ctx.getChannel().isWritable()) + try + { + Thread.sleep(100); + } + catch (Exception ex) + { + Constants.ahessianLogger.warn("",ex); + } + if (future == null) + future = Channels.future(_ctx.getChannel()); + _ctx.sendDownstream(new DownstreamMessageEvent(_ctx.getChannel(), future, _buf, _ctx.getChannel().getRemoteAddress())); + _buf = dynamicBuffer(1024); + _buf.clear(); + return future; + } + + /* (non-Javadoc) + * @see java.io.OutputStream#close() + */ + @Override + public void close() throws IOException + { + _lock.lock(); + _closed = true; + _lock.unlock(); + } + + public void setContext(ChannelHandlerContext ctx) + { + _ctx = ctx; + reset(); + } + + public ChannelHandlerContext getContext() + { + return _ctx; + } + + public void reset() + { + _lock.lock(); + _buf = dynamicBuffer(); + _closed = false; + _lock.unlock(); + } + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/OutputStreamEncoder.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/OutputStreamEncoder.java new file mode 100644 index 0000000000..2c4235de2f --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/OutputStreamEncoder.java @@ -0,0 +1,163 @@ +package org.rzo.netty.ahessian.io; + +import java.io.IOException; +import java.io.OutputStream; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.SimpleChannelHandler; +import org.rzo.netty.ahessian.stopable.StopableHandler; + +/** + * Encodes bytes written to an {@link OutputStream} into a {@link ChannelBuffer} + * . A typical setup for a serialization protocol in a TCP/IP socket would be: + * + *
+ * {@link ChannelPipeline} pipeline = ...; + * + * // Encoder + * pipeline.addLast("outputStream", new {@link handler.io.OutputStream}()); + * pipeline.addLast("outputHandler", new MyOutputHandler()); + * + * // Decoder + * pipeline.addLast("inputStream", new {@link handler.io.InputStream}()); + * pipeline.addLast("inputHandler", new MyInputHandler()); + *+ * + * and then, within the handler you can use a {@link java.io.InputStream} or + * {@link java.io.OutputStream} instead of a {@link ChannelBuffer} as a message:
+ * // synchronized for multithreaded environment to avoid messages mixing + * synchronized public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception + * { + * byte[] message = (byte[]) e.getMessage(); + * OutputStream out = OutputStreamEncoder.getOutputStream(ctx); + * out.write(message); + * // if this is the last chunk of bytes we should flush the output + * out.flush(); + * // netty seems to require this, so that the boss thread may read input from the channel + * Thread.yield(); + * } + * + *+ * + *
+ * void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + * { + * // message received is called only once to deliver the input stream + * // it is called in a separate thread and not in the netty worker thread. + * // incoming bytes are consumed in this method. + * // the stream is closed once the channel is disconnected + * InputStream in = (InputStream) evt.getMessage(); + * + * while (ctx.getChannel().isConnected()) + * { + * // parse the incoming stream and forward the result to the next handler + * Channels.fireMessageReceived(ctx, parseReply(in)); + * } + * } + *+ */ +public class OutputStreamEncoder extends SimpleChannelHandler implements StopableHandler +{ + volatile OutputStreamBuffer _buffer = null; + private boolean _stopEnabled = true; + boolean _crcCheck = false; + + public OutputStreamEncoder() + { + + } + + public OutputStreamEncoder(boolean crcCheck) + { + _crcCheck = crcCheck; + } + + /* (non-Javadoc) + * @see org.jboss.netty.channel.SimpleChannelHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent) + */ + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception + { + if (_buffer == null) + { + if (_crcCheck) + _buffer = new CRCOutputStream(ctx); + else + _buffer = new OutputStreamBuffer(ctx); + ctx.setAttachment(_buffer); + } + else + _buffer.setContext(ctx); + ctx.sendUpstream(e); + } + + /* (non-Javadoc) + * @see org.jboss.netty.channel.SimpleChannelHandler#channelDisconnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent) + */ + @Override + public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception + { + if (_buffer != null) + { + _buffer.close(); + } + ctx.sendUpstream(e); + } + + /** + * Helper method: Gets the output stream from the pipeline of a given context. + * + * @param ctx the context + * + * @return the output stream + */ + public static OutputStream getOutputStream(ChannelHandlerContext ctx) + { + return (OutputStream) ctx.getPipeline().getContext(OutputStreamEncoder.class).getAttachment(); + } + + public static OutputStreamEncoder getOutputEncoder(ChannelHandlerContext ctx) + { + return (OutputStreamEncoder) ctx.getPipeline().getContext(OutputStreamEncoder.class).getHandler(); + } + + public OutputStreamBuffer getBuffer() + { + return _buffer; + } + + public boolean isStopEnabled() + { + return _stopEnabled ; + } + + public void setStopEnabled(boolean stopEnabled) + { + _stopEnabled = stopEnabled; + } + + public void stop() + { + try + { + _buffer.close(); + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + _buffer = null; + } + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/PullInputStreamConsumer.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/PullInputStreamConsumer.java new file mode 100644 index 0000000000..07c5ecb09d --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/PullInputStreamConsumer.java @@ -0,0 +1,149 @@ +package org.rzo.netty.ahessian.io; + +import java.io.InputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.rzo.netty.ahessian.Constants; +import org.rzo.netty.ahessian.stopable.StopableHandler; +import org.rzo.netty.ahessian.utils.MyReentrantLock; + +public class PullInputStreamConsumer extends SimpleChannelUpstreamHandler implements StopableHandler +{ + final InputStreamConsumer _consumer; + final Executor _executor; + final Lock _lock = new MyReentrantLock(); + final Condition _hasData = _lock.newCondition(); + volatile boolean _stop = false; + volatile ChannelHandlerContext _ctx; + volatile InputStream _inputStream; + volatile boolean _waiting = false; + static AtomicInteger _threadCounter = new AtomicInteger(0); + private boolean _stopEnabled = true; + + + public PullInputStreamConsumer(InputStreamConsumer consumer, Executor executor) + { + _consumer = consumer; + _executor = executor; + + _executor.execute(new Runnable() + { + public void run() + { + String tName = Thread.currentThread().getName(); + Thread.currentThread().setName("ahessian-PullInputStreamConsumer-#"+_threadCounter.incrementAndGet()); + try + { + waitForData(); + while (!_stop) + { + _consumer.consume(_ctx, _inputStream); + waitForData(); + } + } + finally + { + Thread.currentThread().setName(tName); + _threadCounter.decrementAndGet(); + } + } + }); + } + + private void waitForData() + { + //System.out.println("wait for data"); + while (! _stop &&( _consumer == null || _consumer.isBufferEmpty() || _ctx == null || !_ctx.getChannel().isConnected())) + { + + _lock.lock(); + try + { + _waiting = true; + _hasData.await(500, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + Constants.ahessianLogger.warn("", e); + } + finally + { + _waiting = false; + _lock.unlock(); + } + } + //System.out.println("got data"); + } + + + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent evnt) throws Exception + { + if (_ctx != ctx) + _ctx = ctx; + if (_inputStream != evnt.getMessage()) + { + _inputStream = (InputStream) evnt.getMessage(); + ((InputStreamBuffer)_inputStream).setReadTimeout(-1); + } + if (_waiting) + { + _lock.lock(); + try + { + _hasData.signal(); + } + finally + { + _lock.unlock(); + } + } + } + + public void channelConnected( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception + { + _lock.lock(); + try + { + _consumer.setContext(ctx); + _ctx = ctx; + } + finally + { + _lock.unlock(); + } + ctx.sendUpstream(e); + } + + public boolean isStopEnabled() + { + return _stopEnabled ; + } + + public void setStopEnabled(boolean stopEnabled) + { + _stopEnabled = stopEnabled; + } + + public void stop() + { + _stop = true; + } + + + + + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/PushInputStreamConsumer.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/PushInputStreamConsumer.java new file mode 100644 index 0000000000..b95e4e1fdf --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/PushInputStreamConsumer.java @@ -0,0 +1,108 @@ +package org.rzo.netty.ahessian.io; + +import java.io.InputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.rzo.netty.ahessian.Constants; +import org.rzo.netty.ahessian.utils.MyReentrantLock; + +public class PushInputStreamConsumer extends SimpleChannelUpstreamHandler +{ + + volatile Lock _lock = new MyReentrantLock(); + AtomicInteger _consumerThreadsCount = new AtomicInteger(0); + + volatile InputStreamConsumer _consumer; + volatile Executor _executor; + + public PushInputStreamConsumer(InputStreamConsumer consumer, Executor executor) + { + _consumer = consumer; + _executor = executor; + } + + @Override + public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent evt) throws Exception + { + // input stream is consumed within a separate thread + // we return the current worker thread to netty, so that it may continue feeding the input stream + _executor.execute(new Runnable() + { + public void run() + { + String tName = Thread.currentThread().getName(); + try + { + PushInputStreamConsumer.this.run(ctx, evt); + } + finally + { + Thread.currentThread().setName(tName); + _consumerThreadsCount.decrementAndGet(); + } + } + }); + + } + + private void run(ChannelHandlerContext ctx, MessageEvent evt) + { + if (_consumer.isBufferEmpty()) + { + // we have nothing to consume + return; + } + + if (_consumerThreadsCount.incrementAndGet() > 2) + { + // there is already a thread consuming and another at the gate to consume the last chunk + _consumerThreadsCount.decrementAndGet(); + return; + } + + Thread.currentThread().setName("ahessian-PushInputStreamConsumer-#"+_consumerThreadsCount.get()); + + + // consume only with one thread at a time + _lock.lock(); + try + { + _consumer.consume(ctx, (InputStream)evt.getMessage()); + } + catch (Exception ex) + { + Constants.ahessianLogger.warn("", ex); + } + finally + { + _consumerThreadsCount.decrementAndGet(); + _lock.unlock(); + } + +} + + public void channelConnected( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception + { + _lock.lock(); + try + { + _consumer.setContext(ctx); + } + finally + { + _lock.unlock(); + } + ctx.sendUpstream(e); + } + + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/package-info.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/package-info.java new file mode 100644 index 0000000000..b07c7820a4 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/io/package-info.java @@ -0,0 +1,9 @@ +/** + * Encoder, decoder which + * transforms a {@link ChannelBuffer} into a Stream and + * vice versa. + *
+ * Executor executor = ... + * HessianProxyFactory proxyFactory = ... + * + * {@link ChannelPipeline} pipeline = ...; + * pipeline.addLast("inputStream", new InputStreamDecoder(_executor)); + * pipeline.addLast("outputStream", new OutputStreamEncoder()); + * pipeline.addLast("hessianReplyDecoder", new HessianRPCReplyDecoder(_factory)); + * pipeline.addLast("hessianCallEncoder", new HessianRPCCallEncoder()); + * pipeline.addLast("hessianHandler", proxyFactory); + *+ * + *
+ * + * ClientBootstrap bootstrap = ... + * ChannelPipelineFactory pipelinetFactory = new ...(proxyFactory) + * bootstrap.setPipelineFactory(...) + * bootstrap.connect(...) + * + * // get a service proxy + * Map options = new HashMap(); + * options.put("id", "myServiceName"); + * // AsynchMyServiceInterface is an interface including the same methods as MyServiceInterface + * //except that the return type is always of type HessianProxyFuture + * AsynchMyServiceInterface service = (AsynchMyServiceInterface) factory.create(AsynchMyServiceInterface.class, getClassLoader(), options); + * + * // invoke a service method + * HessianProxyFuture future = service.myMethod(); + * // wait for the result + * // if an exception is thrown by the server the exception is thrown by the call to the get() method + * Object result = future.get(); + *+ */ + +@ChannelPipelineCoverage("all") +public class HessianProxyFactory extends SimpleChannelHandler implements Constants +{ + private volatile Map
+ * HessianProxyFactory proxyFactory = ... + * + * Map options = new HashMap(); + * options.put("id", "myServiceName"); + * options.put("synch", Boolean.TRUE); + * + * // AsynchMyServiceInterface is an interface including the same methods as MyServiceInterface + * //except that the return type is always of type HessianProxyFuture + * AsynchMyServiceInterface service = (AsynchMyServiceInterface) factory.create(AsynchMyServiceInterface.class, getClassLoader(), options); + * + * // invoke a service method and wait for the result + * Object result = service.myMethod(); + *+ */ +public class SyncHessianProxy implements InvocationHandler +{ + + /** The _handler. */ + AsyncHessianProxy _handler; + long _defaultTimeout = -1; + + /** + * Instantiates a new sync hessian proxy. + * + * @param handler + * the handler + */ + SyncHessianProxy(InvocationHandler handler) + { + _handler = (AsyncHessianProxy) handler; + if (_handler._options != null && _handler._options.get("timeout") != null) + _defaultTimeout = ((Long)_handler._options.get("timeout")).longValue(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, + * java.lang.reflect.Method, java.lang.Object[]) + */ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + if ("equals".equals(method.getName()) || "hashCode".equals(method.getName()) || "getHessianType".equals(method.getName()) || "getHessianURL".equals(method.getName())) + return _handler.invoke(proxy, method, args); + if ("toString".equals(method.getName())) + return "Sync:"+_handler.invoke(proxy, method, args); + long timeout = getTimeout(method.getName()); + if (timeout > 0) + return ((Future)_handler.invoke(proxy, method, args)).get(timeout, TimeUnit.MILLISECONDS); + else + return ((Future)_handler.invoke(proxy, method, args)).get(); + } + + private long getTimeout(String method) + { + if (_handler._options != null && _handler._options.get("timeout."+method) != null) + return ((Long)_handler._options.get("timeout."+method)).longValue(); + return _defaultTimeout; + } + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/rpc/client/package-info.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/rpc/client/package-info.java new file mode 100644 index 0000000000..798850a483 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/rpc/client/package-info.java @@ -0,0 +1,7 @@ +/** + * Provides hessian rpc client side handling + *
+ * public TableData getTableData(Filter filter) + *+ *
+ * public TableData getTableData(Continuation continuation, Filter filter) + * { + * if (requestOk(filter)) + * // add client to client list + * addClient(continuation, filter, context); + * else // or send an error + * // continuation.fault(new Exception...()); + * } + * + * void onTableDataChange() + * { + * // when table data changes send the new data to all attached clients + * for (client : clients) + * { + * TableData newData = ... + * client.getContinuation().send(newData) + * } + * } + * + * void onTableClosed() + * { + * // on shutdown inform all clients that the invocation is completed and no further + * // data will be sent. + * for (client : clients) + * { + * client.getContinuation().completed(null); + * } + * clients.reset(); + * } + + *+ * + */ +public interface Continuation +{ + + /** + * Send an invocation reply to the client + * + * @param result the result + */ + public void send(Object result); + + /** + * Send the last reply to the client and inform that this is the last reply for the invocation request + * + * @param result the result + */ + public void complete(Object result); + + /** + * Send an error to the client and inform that this is the last reply for the invocation request + * + * @param result the result + */ + public void fault(Throwable result); + + /** + * If the client has given us a time out for the invocation calling send, complete or fault after the given + * point in time will result in an exception + * + * @return the tTL + */ + public Date getTTL(); + + public Session getSession(); +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/rpc/server/ContinuationService.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/rpc/server/ContinuationService.java new file mode 100644 index 0000000000..bcee43eae8 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/rpc/server/ContinuationService.java @@ -0,0 +1,163 @@ +package org.rzo.netty.ahessian.rpc.server; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; + +import org.jboss.netty.channel.ChannelHandlerContext; +import org.rzo.netty.ahessian.Constants; +import org.rzo.netty.ahessian.rpc.message.HessianRPCCallMessage; +import org.rzo.netty.ahessian.session.ServerSessionFilter; + +/** + * Wraps an object as a {@link Service}. Call requests are added to a queue. + * Calls are removed from the queue and invoked within a thread from the thread pool. + * If no free threads are available in the pool, execution hangs until a thread is available. + *
+ * // The object to be wrapped, "kind of" implements MyServiceInterface + * // This object implements for each method of the service-api a method with the same name and arguments + * // However an extra argument as to be added to the signature. + * // As first argument of the method an argument of type {@link Continuation} must be added. + * // The continuation object is used to send the result to the client. + * // The result of the method invocation is not sent to the client. + * Object myContinuationServiceObject = ...; + * + * // the netty rpc service handler + * HessianRPCServiceHandler handler = ...; + * + * Service myService = new ContinuationService(myServiceObject, MyServiceInterface.class); + * + * // Clients will access the service through the given name + * handler.addService("myServiceName", myService); + * + *+ */ +public class ContinuationService extends HessianSkeleton +{ + private LinkedBlockingQueue
+ * + * // the object to be wrapped, implements MyServiceInterface + * Object myServiceObject; + * + * // the netty rpc service handler + * HessianRPCServiceHandler handler; + * Executor executor = Executors.newFixedThreadPool(200); + * Service myService = new ExecutorInvokeService(myServiceObject, MyServiceInterface.class, executor); + * + * // Clients will access the service through the given name + * handler.addService("myServiceName", myService); + * + *+ */ + + public class ExecutorInvokeService extends HessianSkeleton implements Constants + { + //public static ThreadLocal threadLocalSession = new ThreadLocal(); + Executor _executor; + + /** + * Instantiates a new immediate invoke service. + * + * @param service the service object implementing apiClass + * @param apiClass the api of the service exposed to the client + * @param factory the netty handler + */ + public ExecutorInvokeService(Object service, Class apiClass, HessianRPCServiceHandler factory, Executor executor) + { + super(service, apiClass, factory); + _executor = executor; + } + + /* (non-Javadoc) + * @see org.rzo.netty.ahessian.rpc.server.HessianSkeleton#messageReceived(org.rzo.netty.ahessian.rpc.HessianRPCCallMessage) + */ + @Override + public void messageReceived(HessianRPCCallMessage message) + { + //threadLocalSession.set(ServerSessionFilter.getSession(ctx)); + invoke(message); + } + + /** + * Invokes the RPC call and sends back the result + * + * @param message the message + */ + void invoke(final HessianRPCCallMessage message) + { + _executor.execute(new Runnable() + { + + public void run() + { + Object result = null; + Object fault = null; + try + { + Method method = getMethod(message); + Object[] args = message.getArgs(); + if (args != null) + { + for (int i=0; i
+ * {@link ChannelPipeline} pipeline = ...; + * pipeline.addLast("inputStream", new InputStreamDecoder(_executor)); + * pipeline.addLast("outputStream", new OutputStreamEncoder()); + * pipeline.addLast("callDecoder", new HessianRPCCallDecoder()); + * pipeline.addLast("replyEncoder", new HessianRPCReplyEncoder()); + * HessianRPCServiceHandler handler = new HessianRPCServiceHandler(executor); + * {@link Service} service = ... + * {@link Executor} executor = ... + * factory.addService("default", new ContinuationService(service, ServiceApi.class, handler, executor)); + * pipeline.addLast("hessianRPCServer", handler); + *+ */ +@ChannelPipelineCoverage("one") +public class HessianRPCServiceHandler extends SimpleChannelUpstreamHandler implements Constants +{ + + /** maps service names to services. */ + private Map
+ * + * // the object to be wrapped, implements MyServiceInterface + * Object myServiceObject; + * + * // the netty rpc service handler + * HessianRPCServiceHandler handler; + * + * Service myService = new ImmediateInvokeService(myServiceObject, MyServiceInterface.class); + * + * // Clients will access the service through the given name + * handler.addService("myServiceName", myService); + * + *+ */ +public class ImmediateInvokeService extends HessianSkeleton implements Constants +{ + + /** + * Instantiates a new immediate invoke service. + * + * @param service the service object implementing apiClass + * @param apiClass the api of the service exposed to the client + * @param factory the netty handler + */ + public ImmediateInvokeService(Object service, Class apiClass, HessianRPCServiceHandler factory) + { + super(service, apiClass, factory); + } + + /* (non-Javadoc) + * @see org.rzo.netty.ahessian.rpc.server.HessianSkeleton#messageReceived(org.rzo.netty.ahessian.rpc.HessianRPCCallMessage) + */ + @Override + public void messageReceived(HessianRPCCallMessage message) + { + ServiceSessionProvider.set(message.getSession()); + invoke(message); + ServiceSessionProvider.remove(); + } + + /** + * Invokes the RPC call and sends back the result + * + * @param message the message + */ + void invoke(HessianRPCCallMessage message) + { + Object result = null; + Object fault = null; + try + { + Method method = getMethod(message); + Object[] args = message.getArgs(); + if (args != null) + { + for (int i=0; i
+ * {@link ChannelPipeline} pipeline = ...; + * + * // Encoder + * pipeline.addLast("outputStream", new {@link io.OutputStream}()); + * pipeline.addLast("hessianEncoder", new {@link HessianEncoder}()); + * + * // Decoder + * pipeline.addLast("inputStream", new {@link io.InputStream}()); + * pipeline.addLast("hessianDecoder", new {@link HessianDecoder}()); + * pipeline.addLast("handler", new MyHandler()); + *+ * and then, within the handler you can use a {@link java.lang.Object} instead of a {@link ChannelBuffer} + * as a message: + *
+ * void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { + * // get the message + * Object msg = e.getMessage(); + * // return the current time + * ch.write(new Date()); + * } + *+ */ + +public class HessianDecoder extends SimpleChannelUpstreamHandler +{ + + /* (non-Javadoc) + * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent) + */ + @Override + public void messageReceived( + ChannelHandlerContext ctx, MessageEvent e) throws Exception + { + InputStream in = (InputStream) e.getMessage(); + try + { + HessianInput hin = new HessianInput(in); + while (true) + { + Object obj = hin.readObject(null); + Channels.fireMessageReceived(ctx, obj); + } + } + catch (Exception ex) + { + Constants.ahessianLogger.debug("", ex); + } + } + + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/serialization/HessianEncoder.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/serialization/HessianEncoder.java new file mode 100644 index 0000000000..a326405f9d --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/serialization/HessianEncoder.java @@ -0,0 +1,54 @@ +package org.rzo.netty.ahessian.serialization; + +import java.io.OutputStream; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelDownstreamHandler; +import org.rzo.netty.ahessian.io.OutputStreamEncoder; + +import com.caucho.hessian4.io.HessianOutput; + +/** + * Encodes the requested {@link java.lang.Object} into a {@link ChannelBuffer}. + * A typical setup for a serialization protocol in a TCP/IP socket would be: + *
+ * {@link ChannelPipeline} pipeline = ...; + * + * // Encoder + * pipeline.addLast("outputStream", new {@link io.OutputStream}()); + * pipeline.addLast("hessianEncoder", new {@link HessianEncoder}()); + * + * // Decoder + * pipeline.addLast("inputStream", new {@link io.InputStream}()); + * pipeline.addLast("hessianDecoder", new {@link HessianDecoder}()); + * pipeline.addLast("handler", new MyHandler()); + *+ * and then, within the handler you can use a {@link java.lang.Object} instead of a {@link ChannelBuffer} + * as a message: + *
+ * void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { + * // get the message + * Object msg = e.getMessage(); + * // return the current time + * ch.write(new Date()); + * } + *+ */ +public class HessianEncoder extends SimpleChannelDownstreamHandler +{ + + /* (non-Javadoc) + * @see org.jboss.netty.channel.SimpleChannelDownstreamHandler#writeRequested(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent) + */ + public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + OutputStream out = OutputStreamEncoder.getOutputStream(ctx); + HessianOutput hout = new HessianOutput(out); + hout.writeObject(e.getMessage()); + hout.flush(); + } + + +} diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/serialization/package-info.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/serialization/package-info.java new file mode 100644 index 0000000000..94465dfad4 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/serialization/package-info.java @@ -0,0 +1,6 @@ +/** + * Encoder, decoder which + * transform a {@link java.lang.Object} into a byte buffer and + * vice versa using hessian serialization. + */ +package org.rzo.netty.ahessian.serialization; \ No newline at end of file diff --git a/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/session/ClientSessionFilter.java b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/session/ClientSessionFilter.java new file mode 100644 index 0000000000..bbff68fed1 --- /dev/null +++ b/javaUtilities/yajsw/src/ahessian/org/rzo/netty/ahessian/session/ClientSessionFilter.java @@ -0,0 +1,222 @@ +package org.rzo.netty.ahessian.session; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineCoverage; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.rzo.netty.ahessian.Constants; +import org.rzo.netty.ahessian.stopable.StopablePipeline; + +/** + * Handles sessions on the client side. + * A typical setup for a protocol in a TCP/IP socket would be: + * + *
+ * // client session filter is an attribute of the ChannelPipelineFactory Class + * // it should not be created with each call to getPipeline() + * // _mixinFactory is a ChannelPipelineFactory which returns MixinPipeline + * _sessionFilter = new ClientSessionFilter(_mixinFactory); + * + * {@link ChannelPipeline} pipeline = ...; + * + * pipeline.addLast("sessionFilter", _sessionFilter); + *+ */ + +@ChannelPipelineCoverage("all") +public class ClientSessionFilter extends SimpleChannelUpstreamHandler +{ + + /** The current session. */ + private Session _session = null; + + /** Indicates if we have received a session. */ + private boolean _hasSession = false; + + /** String to read in the session id from the server */ + private String _sessionId = ""; + + /** Factory for creating session objects. */ + private SessionFactory _factory = new SessionFactory(); + + /** Connected events are intercepted and sent upstream once a session has been established. */ + private ChannelStateEvent _connectedEvent; + + /** The factory for getting a MixinPipeline for a new session */ + private ChannelPipelineFactory _mixinFactory; + + /** Assignment of session-id to pipelines created. //TODO destroy a pipeline if a session is timed out */ + private static Map
+ * // _mixinFactory is a ChannelPipelineFactory which returns MixinPipeline + * {@link ChannelPipeline} pipeline = ...; + * + * pipeline.addLast("sessionFilter", new ServerSessionFilter(_mixinFactory)); + *+ */ +public class ServerSessionFilter extends SimpleChannelUpstreamHandler +{ + + /** Indicates if session has been assigned to the current channel */ + private boolean _hasSession = false; + + /** String for reading in a session id */ + private String _sessionId = ""; + + /** Factory for creating new session objects */ + private SessionFactory _factory = new SessionFactory(); + + /** Connected event is intercepted. It is sent upstream only after a session has been established*/ + private ChannelStateEvent _connectedEvent; + + /** A pipeline factory which returns a MixinPipeline */ + private ChannelPipelineFactory _mixinFactory; + + /** Assignment of session-id to the associated MixinPipeline */ + private static Map
+ * The FileHandler can either write to a specified file, + * or it can write to a rotating set of files. + *
+ * For a rotating set of files, as each file reaches a given size + * limit, it is closed, rotated out, and a new file opened. + * Successively older files are named by adding "0", "1", "2", + * etc into the base filename. + *
+ * By default buffering is enabled in the IO libraries but each log + * record is flushed out when it is complete. + *
+ * By default the XMLFormatter class is used for formatting. + *
+ * Configuration: + * By default each FileHandler is initialized using the following + * LogManager configuration properties. If properties are not defined + * (or have invalid values) then the specified default values are used. + *
+ *
+ * A pattern consists of a string that includes the following special + * components that will be replaced at runtime: + *
+ * Thus for example a pattern of "%t/java%g.log" with a count of 2 + * would typically cause log files to be written on Solaris to + * /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they + * would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log + *
+ * Generation numbers follow the sequence 0, 1, 2, etc. + *
+ * Normally the "%u" unique field is set to 0. However, if the FileHandler + * tries to open the filename and finds the file is currently in use by + * another process it will increment the unique number field and try + * again. This will be repeated until FileHandler finds a file name that + * is not currently in use. If there is a conflict and no "%u" field has + * been specified, it will be added at the end of the filename after a dot. + * (This will be after any automatically added generation number.) + *
+ * Thus if three processes were all trying to log to fred%u.%g.txt then + * they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as + * the first file in their rotating sequences. + *
+ * Note that the use of unique ids to avoid conflicts is only guaranteed + * to work reliably when using a local disk file system. + * + * @version 1.37, 03/23/10 + * @since 1.4 + */ + +public class MyFileHandler extends StreamHandler { + private MeteredStream meter; + private boolean append; + private int limit; // zero => no limit. + private int count; + private String pattern; + private String lockFileName; + private FileOutputStream lockStream; + private File files[]; + private static final int MAX_LOCKS = 100; + private static java.util.HashMap locks = new java.util.HashMap(); + + private FileChangeListner _listener = null; + + interface FileChangeListner + { + void fileChange(File file, boolean added); + } + + // A metered stream is a subclass of OutputStream that + // (a) forwards all its output to a target stream + // (b) keeps track of how many bytes have been written + private class MeteredStream extends OutputStream { + OutputStream out; + int written; + + MeteredStream(OutputStream out, int written) { + this.out = out; + this.written = written; + } + + public void write(int b) throws IOException { + out.write(b); + written++; + } + + public void write(byte buff[]) throws IOException { + out.write(buff); + written += buff.length; + } + + public void write(byte buff[], int off, int len) throws IOException { + out.write(buff,off,len); + written += len; + } + + public void flush() throws IOException { + out.flush(); + } + + public void close() throws IOException { + out.close(); + } + } + + private void open(File fname, boolean append) throws IOException { + int len = 0; + if (append) { + len = (int)fname.length(); + } + if (!fname.getParentFile().exists()) + fname.getParentFile().mkdirs(); + FileOutputStream fout = new FileOutputStream(fname.toString(), append); + BufferedOutputStream bout = new BufferedOutputStream(fout); + meter = new MeteredStream(bout, len); + setOutputStream(meter); + } + + // Private method to configure a FileHandler from LogManager + // properties and/or default values as specified in the class + // javadoc. + private void configure() { + /* + LogManager manager = LogManager.getLogManager(); + + String cname = getClass().getName(); + + pattern = manager.getStringProperty(cname + ".pattern", "%h/java%u.log"); + limit = manager.getIntProperty(cname + ".limit", 0); + if (limit < 0) { + limit = 0; + } + count = manager.getIntProperty(cname + ".count", 1); + if (count <= 0) { + count = 1; + } + append = manager.getBooleanProperty(cname + ".append", false); + setLevel(manager.getLevelProperty(cname + ".level", Level.ALL)); + setFilter(manager.getFilterProperty(cname + ".filter", null)); + setFormatter(manager.getFormatterProperty(cname + ".formatter", new XMLFormatter())); + try { + setEncoding(manager.getStringProperty(cname +".encoding", null)); + } catch (Exception ex) { + try { + setEncoding(null); + } catch (Exception ex2) { + // doing a setEncoding with null should always work. + // assert false; + } + } + */ + } + + + /** + * Construct a default FileHandler. This will be configured + * entirely from LogManager properties (or their default values). + *
+ * @exception IOException if there are IO problems opening the files. + * @exception SecurityException if a security manager exists and if + * the caller does not have LoggingPermission("control")). + * @exception NullPointerException if pattern property is an empty String. + */ + public MyFileHandler() throws IOException, SecurityException { + //checkAccess(); + configure(); + openFiles(); + } + + /** + * Initialize a FileHandler to write to the given filename. + *
+ * The FileHandler is configured based on LogManager + * properties (or their default values) except that the given pattern + * argument is used as the filename pattern, the file limit is + * set to no limit, and the file count is set to one. + *
+ * There is no limit on the amount of data that may be written, + * so use this with care. + * + * @param pattern the name of the output file + * @exception IOException if there are IO problems opening the files. + * @exception SecurityException if a security manager exists and if + * the caller does not have LoggingPermission("control"). + * @exception IllegalArgumentException if pattern is an empty string + */ + public MyFileHandler(String pattern) throws IOException, SecurityException { + if (pattern.length() < 1 ) { + throw new IllegalArgumentException(); + } + //checkAccess(); + configure(); + this.pattern = pattern; + this.limit = 0; + this.count = 1; + openFiles(); + } + + /** + * Initialize a FileHandler to write to the given filename, + * with optional append. + *
+ * The FileHandler is configured based on LogManager + * properties (or their default values) except that the given pattern + * argument is used as the filename pattern, the file limit is + * set to no limit, the file count is set to one, and the append + * mode is set to the given append argument. + *
+ * There is no limit on the amount of data that may be written, + * so use this with care. + * + * @param pattern the name of the output file + * @param append specifies append mode + * @exception IOException if there are IO problems opening the files. + * @exception SecurityException if a security manager exists and if + * the caller does not have LoggingPermission("control"). + * @exception IllegalArgumentException if pattern is an empty string + */ + public MyFileHandler(String pattern, boolean append) throws IOException, SecurityException { + if (pattern.length() < 1 ) { + throw new IllegalArgumentException(); + } + //checkAccess(); + configure(); + this.pattern = pattern; + this.limit = 0; + this.count = 1; + this.append = append; + openFiles(); + } + + /** + * Initialize a FileHandler to write to a set of files. When + * (approximately) the given limit has been written to one file, + * another file will be opened. The output will cycle through a set + * of count files. + *
+ * The FileHandler is configured based on LogManager + * properties (or their default values) except that the given pattern + * argument is used as the filename pattern, the file limit is + * set to the limit argument, and the file count is set to the + * given count argument. + *
+ * The count must be at least 1. + * + * @param pattern the pattern for naming the output file + * @param limit the maximum number of bytes to write to any one file + * @param count the number of files to use + * @exception IOException if there are IO problems opening the files. + * @exception SecurityException if a security manager exists and if + * the caller does not have LoggingPermission("control"). + * @exception IllegalArgumentException if limit < 0, or count < 1. + * @exception IllegalArgumentException if pattern is an empty string + */ + public MyFileHandler(String pattern, int limit, int count) + throws IOException, SecurityException { + if (limit < 0 || count < 1 || pattern.length() < 1) { + throw new IllegalArgumentException(); + } + //checkAccess(); + configure(); + this.pattern = pattern; + this.limit = limit; + this.count = count; + openFiles(); + } + + /** + * Initialize a FileHandler to write to a set of files + * with optional append. When (approximately) the given limit has + * been written to one file, another file will be opened. The + * output will cycle through a set of count files. + *
+ * The FileHandler is configured based on LogManager + * properties (or their default values) except that the given pattern + * argument is used as the filename pattern, the file limit is + * set to the limit argument, and the file count is set to the + * given count argument, and the append mode is set to the given + * append argument. + *
+ * The count must be at least 1.
+ *
+ * @param pattern the pattern for naming the output file
+ * @param limit the maximum number of bytes to write to any one file
+ * @param count the number of files to use
+ * @param append specifies append mode
+ * @exception IOException if there are IO problems opening the files.
+ * @exception SecurityException if a security manager exists and if
+ * the caller does not have LoggingPermission("control").
+ * @exception IllegalArgumentException if limit < 0, or count < 1.
+ * @exception IllegalArgumentException if pattern is an empty string
+ *
+ */
+ public MyFileHandler(String pattern, int limit, int count, boolean append)
+ throws IOException, SecurityException {
+ if (limit < 0 || count < 1 || pattern.length() < 1) {
+ throw new IllegalArgumentException();
+ }
+ //checkAccess();
+ configure();
+ this.pattern = pattern;
+ this.limit = limit;
+ this.count = count;
+ this.append = append;
+ openFiles();
+ }
+
+ public MyFileHandler(String pattern, int limit, int count, boolean append, PatternFormatter fileFormatter, Level logLevel, String encoding) throws SecurityException, IOException
+ {
+ this(pattern, limit, count, append);
+ if (encoding != null)
+ setEncoding(encoding);
+ setFormatter(fileFormatter);
+ setLevel(logLevel);
+ }
+
+ // Private method to open the set of output files, based on the
+ // configured instance variables.
+ private void openFiles() throws IOException {
+ LogManager manager = LogManager.getLogManager();
+ manager.checkAccess();
+ if (count < 1) {
+ throw new IllegalArgumentException("file count = " + count);
+ }
+ if (limit < 0) {
+ limit = 0;
+ }
+
+ // We register our own ErrorManager during initialization
+ // so we can record exceptions.
+ InitializationErrorManager em = new InitializationErrorManager();
+ setErrorManager(em);
+
+ // Create a lock file. This grants us exclusive access
+ // to our set of output files, as long as we are alive.
+ int unique = -1;
+ for (;;) {
+ unique++;
+ if (unique > MAX_LOCKS) {
+ throw new IOException("Couldn't get lock for " + pattern);
+ }
+ // Generate a lock file name from the "unique" int.
+ lockFileName = generate(pattern, 0, unique, count).toString() + ".lck";
+ // Now try to lock that filename.
+ // Because some systems (e.g. Solaris) can only do file locks
+ // between processes (and not within a process), we first check
+ // if we ourself already have the file locked.
+ synchronized(locks) {
+ if (locks.get(lockFileName) != null) {
+ // We already own this lock, for a different FileHandler
+ // object. Try again.
+ continue;
+ }
+ FileChannel fc;
+ try {
+ lockStream = new FileOutputStream(lockFileName);
+ fc = lockStream.getChannel();
+ } catch (IOException ix) {
+ // We got an IOException while trying to open the file.
+ // Try the next file.
+ continue;
+ }
+ try {
+ FileLock fl = fc.tryLock();
+ if (fl == null) {
+ // We failed to get the lock. Try next file.
+ continue;
+ }
+ // We got the lock OK.
+ } catch (IOException ix) {
+ // We got an IOException while trying to get the lock.
+ // This normally indicates that locking is not supported
+ // on the target directory. We have to proceed without
+ // getting a lock. Drop through.
+ }
+ // We got the lock. Remember it.
+ locks.put(lockFileName, lockFileName);
+ break;
+ }
+ }
+
+ files = new File[count];
+ for (int i = 0; i < count; i++) {
+ files[i] = generate(pattern, i, unique, count);
+ }
+
+ // Create the initial log file.
+ if (append) {
+ open(files[0], true);
+ } else {
+ rotate();
+ }
+
+ // Did we detect any exceptions during initialization?
+ Exception ex = em.lastException;
+ if (ex != null) {
+ if (ex instanceof IOException) {
+ throw (IOException) ex;
+ } else if (ex instanceof SecurityException) {
+ throw (SecurityException) ex;
+ } else {
+ throw new IOException("Exception: " + ex);
+ }
+ }
+
+ // Install the normal default ErrorManager.
+ setErrorManager(new ErrorManager());
+ }
+
+ // Generate a filename from a pattern.
+ static File generate(String pattern, int generation, int unique, int count) throws IOException {
+ File file = null;
+ String word = "";
+ int ix = 0;
+ boolean sawg = false;
+ boolean sawu = false;
+ while (ix < pattern.length()) {
+ char ch = pattern.charAt(ix);
+ ix++;
+ char ch2 = 0;
+ if (ix < pattern.length()) {
+ ch2 = Character.toLowerCase(pattern.charAt(ix));
+ }
+ if (ch == '/') {
+ if (file == null) {
+ file = new File(word);
+ } else {
+ file = new File(file, word);
+ }
+ word = "";
+ continue;
+ } else if (ch == '%') {
+ if (ch2 == 't') {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir == null) {
+ tmpDir = System.getProperty("user.home");
+ }
+ file = new File(tmpDir);
+ ix++;
+ word = "";
+ continue;
+ } else if (ch2 == 'h') {
+ file = new File(System.getProperty("user.home"));
+ if (isSetUID()) {
+ // Ok, we are in a set UID program. For safety's sake
+ // we disallow attempts to open files relative to %h.
+ throw new IOException("can't use %h in set UID program");
+ }
+ ix++;
+ word = "";
+ continue;
+ } else if (ch2 == 'g') {
+ word = word + generation;
+ sawg = true;
+ ix++;
+ continue;
+ } else if (ch2 == 'u') {
+ word = word + unique;
+ sawu = true;
+ ix++;
+ continue;
+ } else if (ch2 == '%') {
+ word = word + "%";
+ ix++;
+ continue;
+ }
+ }
+ word = word + ch;
+ }
+ if (count > 1 && !sawg && generation != 0) {
+ word = word + "." + generation;
+ }
+ if (unique > 0 && !sawu && unique != 0) {
+ word = word + "." + unique;
+ }
+ if (word.length() > 0) {
+ if (file == null) {
+ file = new File(word);
+ } else {
+ file = new File(file, word);
+ }
+ }
+ return file;
+ }
+
+ // Rotate the set of output files
+ private synchronized void rotate() {
+ Level oldLevel = getLevel();
+ setLevel(Level.OFF);
+
+ super.close();
+ for (int i = count-2; i >= 0; i--) {
+ File f1 = files[i];
+ File f2 = files[i+1];
+ if (f1.exists()) {
+ if (f2.exists()) {
+ f2.delete();
+ }
+ else if (_listener != null)
+ _listener.fileChange(f2, true);
+ f1.renameTo(f2);
+ }
+ }
+ try {
+ open(files[0], false);
+ } catch (IOException ix) {
+ // We don't want to throw an exception here, but we
+ // report the exception to any registered ErrorManager.
+ reportError(null, ix, ErrorManager.OPEN_FAILURE);
+
+ }
+ setLevel(oldLevel);
+ }
+
+ /**
+ * Format and publish a LogRecord.
+ *
+ * @param record description of the log event. A null record is
+ * silently ignored and is not published
+ */
+ public synchronized void publish(LogRecord record) {
+ if (!isLoggable(record)) {
+ return;
+ }
+ super.publish(record);
+ flush();
+ if (limit > 0 && meter.written >= limit) {
+ // We performed access checks in the "init" method to make sure
+ // we are only initialized from trusted code. So we assume
+ // it is OK to write the target files, even if we are
+ // currently being called from untrusted code.
+ // So it is safe to raise privilege here.
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ rotate();
+ return null;
+ }
+ });
+ }
+ }
+
+ public File currentFile()
+ {
+ return files[0];
+ }
+
+ public LinkedList
+ * It extends The proxy can use HTTP basic authentication if the user and the
+ * password are set.
+ */
+public class HessianProxyFactory implements ServiceProxyFactory /*, ObjectFactory */{
+ protected static Logger log
+ = Logger.getLogger(HessianProxyFactory.class.getName());
+
+ private final ClassLoader _loader;
+
+ private SerializerFactory _serializerFactory;
+
+ private HessianConnectionFactory _connFactory;
+
+ private HessianRemoteResolver _resolver;
+
+ private String _user;
+ private String _password;
+ private String _basicAuth;
+
+ private boolean _isOverloadEnabled = false;
+
+ private boolean _isHessian2Reply = true;
+ private boolean _isHessian2Request = false;
+
+ private boolean _isChunkedPost = true;
+ private boolean _isDebug = false;
+
+ private long _readTimeout = -1;
+ private long _connectTimeout = -1;
+
+ /**
+ * Creates the new proxy factory.
+ */
+ public HessianProxyFactory()
+ {
+ this(Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * Creates the new proxy factory.
+ */
+ public HessianProxyFactory(ClassLoader loader)
+ {
+ _loader = loader;
+ _resolver = new HessianProxyResolver(this);
+ }
+
+ /**
+ * Sets the user.
+ */
+ public void setUser(String user)
+ {
+ _user = user;
+ _basicAuth = null;
+ }
+
+ /**
+ * Sets the password.
+ */
+ public void setPassword(String password)
+ {
+ _password = password;
+ _basicAuth = null;
+ }
+
+ public String getBasicAuth()
+ {
+ if (_basicAuth != null)
+ return _basicAuth;
+
+ else if (_user != null && _password != null)
+ return "Basic " + base64(_user + ":" + _password);
+
+ else
+ return null;
+ }
+
+ /**
+ * Sets the connection factory to use when connecting
+ * to the Hessian service.
+ */
+ public void setConnectionFactory(HessianConnectionFactory factory)
+ {
+ _connFactory = factory;
+ }
+
+ /**
+ * Returns the connection factory to be used for the HTTP request.
+ */
+ public HessianConnectionFactory getConnectionFactory()
+ {
+ if (_connFactory == null) {
+ _connFactory = createHessianConnectionFactory();
+ _connFactory.setHessianProxyFactory(this);
+ }
+
+ return _connFactory;
+ }
+
+ /**
+ * Sets the debug
+ */
+ public void setDebug(boolean isDebug)
+ {
+ _isDebug = isDebug;
+ }
+
+ /**
+ * Gets the debug
+ */
+ public boolean isDebug()
+ {
+ return _isDebug;
+ }
+
+ /**
+ * Returns true if overloaded methods are allowed (using mangling)
+ */
+ public boolean isOverloadEnabled()
+ {
+ return _isOverloadEnabled;
+ }
+
+ /**
+ * set true if overloaded methods are allowed (using mangling)
+ */
+ public void setOverloadEnabled(boolean isOverloadEnabled)
+ {
+ _isOverloadEnabled = isOverloadEnabled;
+ }
+
+ /**
+ * Set true if should use chunked encoding on the request.
+ */
+ public void setChunkedPost(boolean isChunked)
+ {
+ _isChunkedPost = isChunked;
+ }
+
+ /**
+ * Set true if should use chunked encoding on the request.
+ */
+ public boolean isChunkedPost()
+ {
+ return _isChunkedPost;
+ }
+
+ /**
+ * The socket timeout on requests in milliseconds.
+ */
+ public long getReadTimeout()
+ {
+ return _readTimeout;
+ }
+
+ /**
+ * The socket timeout on requests in milliseconds.
+ */
+ public void setReadTimeout(long timeout)
+ {
+ _readTimeout = timeout;
+ }
+
+ /**
+ * The socket connection timeout in milliseconds.
+ */
+ public long getConnectTimeout()
+ {
+ return _connectTimeout;
+ }
+
+ /**
+ * The socket connect timeout in milliseconds.
+ */
+ public void setConnectTimeout(long timeout)
+ {
+ _connectTimeout = timeout;
+ }
+
+ /**
+ * True if the proxy can read Hessian 2 responses.
+ */
+ public void setHessian2Reply(boolean isHessian2)
+ {
+ _isHessian2Reply = isHessian2;
+ }
+
+ /**
+ * True if the proxy should send Hessian 2 requests.
+ */
+ public void setHessian2Request(boolean isHessian2)
+ {
+ _isHessian2Request = isHessian2;
+
+ if (isHessian2)
+ _isHessian2Reply = true;
+ }
+
+ /**
+ * Returns the remote resolver.
+ */
+ public HessianRemoteResolver getRemoteResolver()
+ {
+ return _resolver;
+ }
+
+ /**
+ * Sets the serializer factory.
+ */
+ public void setSerializerFactory(SerializerFactory factory)
+ {
+ _serializerFactory = factory;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ public SerializerFactory getSerializerFactory()
+ {
+ if (_serializerFactory == null)
+ _serializerFactory = new SerializerFactory(_loader);
+
+ return _serializerFactory;
+ }
+
+ protected HessianConnectionFactory createHessianConnectionFactory()
+ {
+ String className
+ = System.getProperty(HessianConnectionFactory.class.getName());
+
+ HessianConnectionFactory factory = null;
+
+ try {
+ if (className != null) {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+
+ Class> cl = Class.forName(className, false, loader);
+
+ factory = (HessianConnectionFactory) cl.newInstance();
+
+ return factory;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return new HessianURLConnectionFactory();
+ }
+ /**
+ * Creates a new proxy with the specified URL. The API class uses
+ * the java.api.class value from _hessian_
+ *
+ * @param url the URL where the client object is located.
+ *
+ * @return a proxy to the object with the specified interface.
+ */
+ public Object create(String url)
+ throws MalformedURLException, ClassNotFoundException
+ {
+ HessianMetaInfoAPI metaInfo;
+
+ metaInfo = (HessianMetaInfoAPI) create(HessianMetaInfoAPI.class, url);
+
+ String apiClassName =
+ (String) metaInfo._hessian_getAttribute("java.api.class");
+
+ if (apiClassName == null)
+ throw new HessianRuntimeException(url + " has an unknown api.");
+
+ Class> apiClass = Class.forName(apiClassName, false, _loader);
+
+ return create(apiClass, url);
+ }
+
+ /**
+ * Creates a new proxy with the specified URL. The returned object
+ * is a proxy with the interface specified by api.
+ *
+ * A successful completion will have a single value:
+ *
+ * The call expects the following protocol data
+ *
+ * The call expects the following protocol data
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * HessianInput is unbuffered, so any client needs to provide
+ * its own buffering.
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * The call expects the following protocol data
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * 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.
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A message contains several objects encapsulated by a length A successful completion will have a single value:
+ *
+ * A streaming message starts with 'P' A streaming contains a set of chunks, ending with a zero chunk.
+ * Each chunk is a length followed by data where the length is
+ * encoded by (b1xxxxxxxx)* b0xxxxxxxx HessianInput is unbuffered, so any client needs to provide
+ * its own buffering.
+ *
+ * A successful completion will have a single value:
+ *
+ * The call expects the following protocol data
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * 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.
+ *
+ * A successful completion will have a single value:
+ *
+ * A successful completion will have a single value:
+ *
+ * HessianSerializerInput is unbuffered, so any client needs to provide
+ * its own buffering.
+ *
+ * HessianOutput is unbuffered, so any client needs to provide
+ * its own buffering.
+ *
+ *
+ * The Log Formatter will use the following formatting tokens LoggerName %LOGGER% Level %LEVEL% Time %TIME% Message %MESSAGE% SourceClassName %SOURCECLASS% SourceMethodName %SOURCEMETHOD% Exception Message %EXCEPTION% ExceptionStackTrace %STACKTRACE% Parameter %PARAM%
+ *
+ *
+ * The default log format is "[%LOGGER% - %LEVEL%] %TIME%: %MESSAGE%" And
+ * exception format is [%LOGGER% - %LEVEL%] %TIME% %MESSAGE% \n Exception:
+ * %EXCEPTION% \n %STACKTRACE% Apart from this the time format may be
+ * specified in satand java time format in the timeFormat variable The
+ * default time format is "dd-MMM-yyy; HH:mm:ss".
+ */
+
+ private String logPattern;
+
+ /** The exception pattern. */
+ private String exceptionPattern;
+
+ /** The time format. */
+ private String timeFormat;
+
+ /** The log message format. */
+ private MessageFormat logMessageFormat;
+
+ /** The exception message format. */
+ private MessageFormat exceptionMessageFormat;
+
+ /** The date format. */
+ private DateFormat dateFormat;
+
+ /**
+ * Instantiates a new pattern formatter.
+ */
+ public PatternFormatter()
+ {
+ LogManager manager = LogManager.getLogManager();
+ String cname = getClass().getName();
+
+ timeFormat = manager.getProperty(cname + ".timeFormat");
+
+ if (timeFormat == null)
+ {
+ timeFormat = "dd-MMM-yyy; HH:mm:ss";
+ }
+ setTimeFormat(timeFormat);
+
+ logPattern = manager.getProperty(cname + ".logPattern");
+ if (logPattern == null)
+ {
+ logPattern = "[{0} - {1}] {2}: {3} \n";
+ }
+ setLogPattern(logPattern);
+
+ exceptionPattern = manager.getProperty(cname + ".exceptionPattern");
+ if (exceptionPattern == null)
+ {
+ exceptionPattern = "[{0} - {1}] {2} {3} \nException in {4}: {6} \n{7} ";
+ }
+ setExceptionPattern(exceptionPattern);
+
+ logMessageFormat = new MessageFormat(logPattern);
+ exceptionMessageFormat = new MessageFormat(exceptionPattern);
+
+ dateFormat = new SimpleDateFormat(timeFormat);
+ }
+
+ /**
+ * Sets the time format.
+ *
+ * @param timeFormat
+ * the new time format
+ */
+ public void setTimeFormat(String timeFormat)
+ {
+ this.timeFormat = timeFormat;
+ dateFormat = new SimpleDateFormat(timeFormat);
+ }
+
+ /**
+ * Sets the log pattern.
+ *
+ * @param logFormat
+ * the new log pattern
+ */
+ public void setLogPattern(String logFormat)
+ {
+ logFormat = logFormat.replace("%LOGGER%", "{0}");
+ logFormat = logFormat.replace("%LEVEL%", "{1}");
+ logFormat = logFormat.replace("%TIME%", "{2}");
+ logFormat = logFormat.replace("%MESSAGE%", "{3}");
+ logFormat = logFormat.replace("%SOURCECLASS%", "{4}");
+ logFormat = logFormat.replace("%SOURCEMETHOD%", "{5}");
+ logFormat = logFormat.replace("%PARAM0%", "{6}");
+ logFormat = logFormat.replace("%PARAM1%", "{7}");
+
+ this.logPattern = logFormat;
+
+ logMessageFormat = new MessageFormat(logPattern);
+ }
+
+ /**
+ * Sets the exception pattern.
+ *
+ * @param exceptionFormat
+ * the new exception pattern
+ */
+ public void setExceptionPattern(String exceptionFormat)
+ {
+ exceptionFormat = exceptionFormat.replace("%LOGGER%", "{0}");
+ exceptionFormat = exceptionFormat.replace("%LEVEL%", "{1}");
+ exceptionFormat = exceptionFormat.replace("%TIME%", "{2}");
+ exceptionFormat = exceptionFormat.replace("%MESSAGE%", "{3}");
+ exceptionFormat = exceptionFormat.replace("%SOURCECLASS%", "{4}");
+ exceptionFormat = exceptionFormat.replace("%SOURCEMETHOD%", "{5}");
+ exceptionFormat = exceptionFormat.replace("%EXCEPTION%", "{6}");
+ exceptionFormat = exceptionFormat.replace("%STACKTRACE%", "{7}");
+
+ this.exceptionPattern = exceptionFormat;
+
+ exceptionMessageFormat = new MessageFormat(logPattern);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.logging.Formatter#format(java.util.logging.LogRecord)
+ */
+ @Override
+ public String format(LogRecord record)
+ {
+ Date time = new Date(record.getMillis());
+ String formattedTime = dateFormat.format(time);
+
+ String logMessage = "";
+
+ if (record.getThrown() == null)
+ {
+ Object[] log =
+ { record.getLoggerName(), record.getLevel(), formattedTime, record.getMessage(), record.getSourceClassName(),
+ record.getSourceMethodName(), record.getParameters() == null ? "" : record.getParameters()[0], record.getParameters() == null ? "" : record.getParameters()[1] };
+
+ logMessage = logMessageFormat.format(log);
+ }
+ else
+ {
+ String stack = getStackLayout(record.getThrown(), "");
+
+ Object[] log =
+ { record.getLoggerName(), record.getLevel(), formattedTime, record.getMessage(), record.getSourceClassName(),
+ record.getSourceMethodName(), record.getThrown().getMessage(), stack };
+
+ logMessage = exceptionMessageFormat.format(log);
+ }
+ return logMessage;
+ }
+
+ /**
+ * Gets the stack layout.
+ *
+ * @param t
+ * the t
+ * @param indenter
+ * the indenter
+ *
+ * @return the stack layout
+ */
+ private String getStackLayout(Throwable t, String indenter)
+ {
+ indenter = indenter + " ";
+
+ StackTraceElement[] ste = t.getStackTrace();
+ String stack = indenter + ste[0].toString();
+ for (int i = 1; i < ste.length; i++)
+ {
+ stack = stack + "\n" + indenter + ste[i];
+ }
+
+ String innerStack = "";
+ if (t.getCause() != null)
+ {
+ innerStack = indenter + "Caused by: " + t.getCause().getMessage() + "\n";
+ innerStack = innerStack + getStackLayout(t.getCause(), indenter);
+ }
+ stack = stack + "\n" + innerStack;
+
+ return stack;
+ }
+
+ /**
+ * Gets the exception pattern.
+ *
+ * @return the exception pattern
+ */
+ public String getExceptionPattern()
+ {
+ return exceptionPattern;
+ }
+
+ /**
+ * Gets the log pattern.
+ *
+ * @return the log pattern
+ */
+ public String getLogPattern()
+ {
+ return logPattern;
+ }
+
+ /**
+ * Gets the time format.
+ *
+ * @return the time format
+ */
+ public String getTimeFormat()
+ {
+ return timeFormat;
+ }
+
+}
diff --git a/javaUtilities/yajsw/src/build/java/org/rzo/builder/JarBuilder.java b/javaUtilities/yajsw/src/build/java/org/rzo/builder/JarBuilder.java
new file mode 100644
index 0000000000..ea1eb8d8f7
--- /dev/null
+++ b/javaUtilities/yajsw/src/build/java/org/rzo/builder/JarBuilder.java
@@ -0,0 +1,140 @@
+package org.rzo.builder;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.VFS;
+import org.rzo.yajsw.util.VFSUtils;
+
+/**
+ *
+ * compress multiple jar files into a single jar file
+ *
+ * 1. run a program with -verbose:class, so that all required classes are loaded and logged
+ * 2. write log to a file
+ * 3. call java JarBuilder log-file newjar
+ *
+ * JarBuilder will build a jar with the files used by the application
+ *
+ */
+
+public class JarBuilder
+{
+ // multimap: assignment of jar files to class files used in the application
+ MapProfilingSecurityManager
is a Java security manager that profiles
+ * what resources an application accesses, and in what manner --- e.g., read, write, etc. It does not enforce a
+ * security policy, but rather produces a starting point for crafting one.
+ * java.lang.SecurityManager
and overrides the two forms of the checkPermission()
method.
+ * For each call to checkPermission()
, ProfilingSecurityManager
first guards against the
+ * condition that it itself induced the call to checkPermission()
, which would result in
+ * unterminated recursion. If a call to checkPermission()
resulted from a call outside
+ * ProfilingSecurityManager
, the current context is examined and each class found therein is
+ * profiled as needing access to the java.security.Permission
in question.
+ *
+ * Profiling is manifested as a writing to System.out
a "grant" rule for each java.security.Permission
requested
+ * on a per CodeBase
basis.
+ *
+ * The implementation here does some very simple rule caching. If a rule has been seen previously, it is not output to System.out.
+ * The caching cannot prevent a security check, but it can reduce I/O during profiling.
+ *
+ * @author Mark S. Petrovic
+ */
+public class ProfilingSecurityManager extends SecurityManager {
+
+ /* Variables of pure convenience */
+ final private String thisClassName;
+ final private String thisCodeSourceURLString;
+ final private String psmMsg = "ProfilingSecurityManager";
+ final private ArrayList
+ * String url = "http://localhost:8080/ejb/hello";
+ * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
+ *
+ *
+ * After creation, the stub can be like a regular Java class. Because
+ * it makes remote calls, it can throw more exceptions than a Java class.
+ * In particular, it may throw protocol exceptions.
+ *
+ * The factory can also be configured as a JNDI resource. The factory
+ * expects to parameters: "type" and "url", corresponding to the two
+ * arguments to create
+ *
+ * In Resin 3.0, the above example would be configured as:
+ *
+ * <reference>
+ * <jndi-name>hessian/hello</jndi-name>
+ * <factory>com.caucho.hessian.client.HessianProxyFactory</factory>
+ * <init-param url="http://localhost:8080/ejb/hello"/>
+ * <init-param type="test.HelloHome"/>
+ * </reference>
+ *
+ *
+ * To get the above resource, use JNDI as follows:
+ *
+ * Context ic = new InitialContext();
+ * HelloHome hello = (HelloHome) ic.lookup("java:comp/env/hessian/hello");
+ *
+ * System.out.println("Hello: " + hello.helloWorld());
+ *
+ *
+ * Authentication
+ *
+ *
+ * String url = "http://localhost:8080/ejb/hello");
+ * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
+ *
+ *
+ * @param api the interface the proxy class needs to implement
+ * @param url the URL where the client object is located.
+ *
+ * @return a proxy to the object with the specified interface.
+ */
+ public Object create(Class api, String urlName)
+ throws MalformedURLException
+ {
+ return create(api, urlName, _loader);
+ }
+
+ /**
+ * Creates a new proxy with the specified URL. The returned object
+ * is a proxy with the interface specified by api.
+ *
+ *
+ * String url = "http://localhost:8080/ejb/hello");
+ * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
+ *
+ *
+ * @param api the interface the proxy class needs to implement
+ * @param url the URL where the client object is located.
+ *
+ * @return a proxy to the object with the specified interface.
+ */
+ public Object create(Class api, String urlName, ClassLoader loader)
+ throws MalformedURLException
+ {
+ URL url = new URL(urlName);
+
+ return create(api, url, loader);
+ }
+
+ /**
+ * Creates a new proxy with the specified URL. The returned object
+ * is a proxy with the interface specified by api.
+ *
+ *
+ * String url = "http://localhost:8080/ejb/hello");
+ * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
+ *
+ *
+ * @param api the interface the proxy class needs to implement
+ * @param url the URL where the client object is located.
+ *
+ * @return a proxy to the object with the specified interface.
+ */
+ public Object create(Class> api, URL url, ClassLoader loader)
+ {
+ if (api == null)
+ throw new NullPointerException("api must not be null for HessianProxyFactory.create()");
+ InvocationHandler handler = null;
+
+ handler = new HessianProxy(url, this, api);
+
+ return Proxy.newProxyInstance(loader,
+ new Class[] { api,
+ HessianRemoteObject.class },
+ handler);
+ }
+
+ public AbstractHessianInput getHessianInput(InputStream is)
+ {
+ return getHessian2Input(is);
+ }
+
+ public AbstractHessianInput getHessian1Input(InputStream is)
+ {
+ AbstractHessianInput in;
+
+ if (_isDebug)
+ is = new HessianDebugInputStream(is, new PrintWriter(System.out));
+
+ in = new HessianInput(is);
+
+ in.setRemoteResolver(getRemoteResolver());
+
+ in.setSerializerFactory(getSerializerFactory());
+
+ return in;
+ }
+
+ public AbstractHessianInput getHessian2Input(InputStream is)
+ {
+ AbstractHessianInput in;
+
+ if (_isDebug)
+ is = new HessianDebugInputStream(is, new PrintWriter(System.out));
+
+ in = new Hessian2Input(is);
+
+ in.setRemoteResolver(getRemoteResolver());
+
+ in.setSerializerFactory(getSerializerFactory());
+
+ return in;
+ }
+
+ public AbstractHessianOutput getHessianOutput(OutputStream os)
+ {
+ AbstractHessianOutput out;
+
+ if (_isHessian2Request)
+ out = new Hessian2Output(os);
+ else {
+ HessianOutput out1 = new HessianOutput(os);
+ out = out1;
+
+ if (_isHessian2Reply)
+ out1.setVersion(2);
+ }
+
+ out.setSerializerFactory(getSerializerFactory());
+
+ return out;
+ }
+
+// /**
+// * JNDI object factory so the proxy can be used as a resource.
+// */
+// public Object getObjectInstance(Object obj, Name name,
+// Context nameCtx, Hashtable,?> environment)
+// throws Exception
+// {
+// Reference ref = (Reference) obj;
+//
+// String api = null;
+// String url = null;
+// String user = null;
+// String password = null;
+//
+// for (int i = 0; i < ref.size(); i++) {
+// RefAddr addr = ref.get(i);
+//
+// String type = addr.getType();
+// String value = (String) addr.getContent();
+//
+// if (type.equals("type"))
+// api = value;
+// else if (type.equals("url"))
+// url = value;
+// else if (type.equals("user"))
+// setUser(value);
+// else if (type.equals("password"))
+// setPassword(value);
+// }
+//
+// if (url == null)
+// throw new NamingException("`url' must be configured for HessianProxyFactory.");
+// // XXX: could use meta protocol to grab this
+// if (api == null)
+// throw new NamingException("`type' must be configured for HessianProxyFactory.");
+//
+// Class apiClass = Class.forName(api, false, _loader);
+//
+// return create(apiClass, url);
+// }
+
+ /**
+ * Creates the Base64 value.
+ */
+ private String base64(String value)
+ {
+ StringBuffer cb = new StringBuffer();
+
+ int i = 0;
+ for (i = 0; i + 2 < value.length(); i += 3) {
+ long chunk = (int) value.charAt(i);
+ chunk = (chunk << 8) + (int) value.charAt(i + 1);
+ chunk = (chunk << 8) + (int) value.charAt(i + 2);
+
+ cb.append(encode(chunk >> 18));
+ cb.append(encode(chunk >> 12));
+ cb.append(encode(chunk >> 6));
+ cb.append(encode(chunk));
+ }
+
+ if (i + 1 < value.length()) {
+ long chunk = (int) value.charAt(i);
+ chunk = (chunk << 8) + (int) value.charAt(i + 1);
+ chunk <<= 8;
+
+ cb.append(encode(chunk >> 18));
+ cb.append(encode(chunk >> 12));
+ cb.append(encode(chunk >> 6));
+ cb.append('=');
+ }
+ else if (i < value.length()) {
+ long chunk = (int) value.charAt(i);
+ chunk <<= 16;
+
+ cb.append(encode(chunk >> 18));
+ cb.append(encode(chunk >> 12));
+ cb.append('=');
+ cb.append('=');
+ }
+
+ return cb.toString();
+ }
+
+ public static char encode(long d)
+ {
+ d &= 0x3f;
+ if (d < 26)
+ return (char) (d + 'A');
+ else if (d < 52)
+ return (char) (d + 'a' - 26);
+ else if (d < 62)
+ return (char) (d + '0' - 52);
+ else if (d == 62)
+ return '+';
+ else
+ return '/';
+ }
+}
+
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianProxyResolver.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianProxyResolver.java
new file mode 100644
index 0000000000..047fde6fde
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianProxyResolver.java
@@ -0,0 +1,85 @@
+/*
+ * 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.caucho.hessian4.client;
+
+import java.io.IOException;
+
+import com.caucho.hessian4.io.HessianRemoteResolver;
+
+/**
+ * Looks up remote objects in the proxy.
+ */
+public class HessianProxyResolver implements HessianRemoteResolver {
+ private HessianProxyFactory _factory;
+
+ /**
+ * Creates an uninitialized Hessian remote resolver.
+ */
+ public HessianProxyResolver(HessianProxyFactory factory)
+ {
+ _factory = factory;
+ }
+
+ /**
+ * Looks up a proxy object.
+ */
+ public Object lookup(String type, String url)
+ throws IOException
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+
+ try {
+ Class api = Class.forName(type, false, loader);
+
+ return _factory.create(api, url);
+ } catch (Exception e) {
+ throw new IOException(String.valueOf(e));
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianRuntimeException.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianRuntimeException.java
new file mode 100644
index 0000000000..a8f27a99ff
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianRuntimeException.java
@@ -0,0 +1,107 @@
+/*
+ * 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.caucho.hessian4.client;
+
+/**
+ * Wrapper for protocol exceptions thrown in the proxy.
+ */
+public class HessianRuntimeException extends RuntimeException {
+ private Throwable rootCause;
+
+ /**
+ * Zero-arg constructor.
+ */
+ public HessianRuntimeException()
+ {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianRuntimeException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianRuntimeException(String message, Throwable rootCause)
+ {
+ super(message);
+
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianRuntimeException(Throwable rootCause)
+ {
+ super(String.valueOf(rootCause));
+
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Returns the underlying cause.
+ */
+ public Throwable getRootCause()
+ {
+ return this.rootCause;
+ }
+
+ /**
+ * Returns the underlying cause.
+ */
+ public Throwable getCause()
+ {
+ return getRootCause();
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianURLConnection.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianURLConnection.java
new file mode 100644
index 0000000000..2ad61eba9c
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianURLConnection.java
@@ -0,0 +1,203 @@
+/*
+ * 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.caucho.hessian4.client;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * Internal connection to a server. The default connection is based on
+ * java.net
+ */
+public class HessianURLConnection extends AbstractHessianConnection {
+ private URL _url;
+ private URLConnection _conn;
+
+ private int _statusCode;
+ private String _statusMessage;
+
+ private InputStream _inputStream;
+ private InputStream _errorStream;
+
+ HessianURLConnection(URL url, URLConnection conn)
+ {
+ _url = url;
+ _conn = conn;
+ }
+
+ /**
+ * Adds a HTTP header.
+ */
+ public void addHeader(String key, String value)
+ {
+ _conn.setRequestProperty(key, value);
+ }
+
+ /**
+ * Returns the output stream for the request.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ return _conn.getOutputStream();
+ }
+
+ /**
+ * Sends the request
+ */
+ public void sendRequest()
+ throws IOException
+ {
+ if (_conn instanceof HttpURLConnection) {
+ HttpURLConnection httpConn = (HttpURLConnection) _conn;
+
+ _statusCode = 500;
+
+ try {
+ _statusCode = httpConn.getResponseCode();
+ } catch (Exception e) {
+ }
+
+ parseResponseHeaders(httpConn);
+
+ InputStream is = null;
+
+ if (_statusCode != 200) {
+ StringBuffer sb = new StringBuffer();
+ int ch;
+
+ try {
+ is = httpConn.getInputStream();
+
+ if (is != null) {
+ while ((ch = is.read()) >= 0)
+ sb.append((char) ch);
+
+ is.close();
+ }
+
+ is = httpConn.getErrorStream();
+ if (is != null) {
+ while ((ch = is.read()) >= 0)
+ sb.append((char) ch);
+ }
+
+ _statusMessage = sb.toString();
+ } catch (FileNotFoundException e) {
+ throw new HessianConnectionException("HessianProxy cannot connect to '" + _url, e);
+ } catch (IOException e) {
+ if (is == null)
+ throw new HessianConnectionException(_statusCode + ": " + e, e);
+ else
+ throw new HessianConnectionException(_statusCode + ": " + sb, e);
+ }
+
+ if (is != null)
+ is.close();
+
+ throw new HessianConnectionException(_statusCode + ": " + sb.toString());
+ }
+ }
+ }
+
+ protected void parseResponseHeaders(HttpURLConnection conn)
+ throws IOException
+ {
+ }
+
+ /**
+ * Returns the status code.
+ */
+ public int getStatusCode()
+ {
+ return _statusCode;
+ }
+
+ /**
+ * Returns the status string.
+ */
+ public String getStatusMessage()
+ {
+ return _statusMessage;
+ }
+
+ /**
+ * Returns the InputStream to the result
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ return _conn.getInputStream();
+ }
+
+ /**
+ * Close/free the connection
+ */
+ public void close()
+ {
+ }
+
+ /**
+ * Disconnect the connection
+ */
+ public void destroy()
+ {
+ URLConnection conn = _conn;
+ _conn = null;
+
+ if (conn instanceof HttpURLConnection)
+ ((HttpURLConnection) conn).disconnect();
+ }
+}
+
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianURLConnectionFactory.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianURLConnectionFactory.java
new file mode 100644
index 0000000000..5665a9e3ba
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/HessianURLConnectionFactory.java
@@ -0,0 +1,117 @@
+/*
+ * 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.caucho.hessian4.client;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Internal factory for creating connections to the server. The default
+ * factory is java.net
+ */
+public class HessianURLConnectionFactory implements HessianConnectionFactory {
+ private static final Logger log
+ = Logger.getLogger(HessianURLConnectionFactory.class.getName());
+
+ private HessianProxyFactory _proxyFactory;
+
+ public void setHessianProxyFactory(HessianProxyFactory factory)
+ {
+ _proxyFactory = factory;
+ }
+
+ /**
+ * Opens a new or recycled connection to the HTTP server.
+ */
+ public HessianConnection open(URL url)
+ throws IOException
+ {
+ if (log.isLoggable(Level.FINER))
+ log.finer(this + " open(" + url + ")");
+
+ URLConnection conn = url.openConnection();
+
+ // HttpURLConnection httpConn = (HttpURLConnection) conn;
+ // httpConn.setRequestMethod("POST");
+ // conn.setDoInput(true);
+
+ long connectTimeout = _proxyFactory.getConnectTimeout();
+
+ if (connectTimeout >= 0)
+ conn.setConnectTimeout((int) connectTimeout);
+
+ conn.setDoOutput(true);
+
+ long readTimeout = _proxyFactory.getReadTimeout();
+
+ if (readTimeout > 0) {
+ try {
+ conn.setReadTimeout((int) readTimeout);
+ } catch (Throwable e) {
+ }
+ }
+
+ /*
+ // Used chunked mode when available, i.e. JDK 1.5.
+ if (_proxyFactory.isChunkedPost() && conn instanceof HttpURLConnection) {
+ try {
+ HttpURLConnection httpConn = (HttpURLConnection) conn;
+
+ httpConn.setChunkedStreamingMode(8 * 1024);
+ } catch (Throwable e) {
+ }
+ }
+ */
+
+ return new HessianURLConnection(url, conn);
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/package.html b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/package.html
new file mode 100644
index 0000000000..0b15710b98
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/client/package.html
@@ -0,0 +1,59 @@
+
+
+Portable client code for using Hessian services. Since this package is
+independent of all Resin code, its classes can be copied to a
+non-Resin client jar.
+
+RPC Proxy Clients - HessianProxyFactory
+
+Most application clients will use HessianProxyFactory to
+create stub objects. The stub objects can be called with normal
+Java calls. Because the objects are remote, the client application needs
+to be able to deal with IOException caused by an unavailable server or
+a protocol error.
+
+
+import com.caucho.hessian.client.HessianProxyFactory;
+
+...
+
+URL url = new URL("http://localhost:8080/ejb/hello");
+HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
+
+System.out.println("hello: " + hello.hello());
+
+
+Serialization
+
+Since the Hessian protocol serializes Java objects to XML, the
+HessianSerializerOutput and HessianSerializerInput
+can be used for serialization.
+
+Serialization
+
+OutputStream os = new FileOutputStream("test.xml");
+HessianOutput out = new HessianSerializerOutput(os);
+
+out.writeObject(obj);
+os.close();
+
+
+Deserialization
+
+InputStream is = new FileInputStream("test.xml");
+HessianInput in = new HessianSerializerInput(in);
+
+Object obj = in.readObject();
+
+is.close();
+
+
+MicroHessianInput and MicroHessianOutput
+
+These two classes only require classes from Java MicroEdition. So they
+can be extracted separately into a hessian-micro.jar. Because of this
+restriction and their small size, these two classes
+are ideal for limited size devices like mobile phones and PDAs.
+
+
+
\ No newline at end of file
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractDeserializer.java
new file mode 100644
index 0000000000..fd34993915
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractDeserializer.java
@@ -0,0 +1,167 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializing an object.
+ */
+public class AbstractDeserializer implements Deserializer {
+ public static final NullDeserializer NULL = new NullDeserializer();
+
+ public Class> getType()
+ {
+ return Object.class;
+ }
+
+ public boolean isReadResolve()
+ {
+ return false;
+ }
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ Object obj = in.readObject();
+
+ String className = getClass().getName();
+
+ if (obj != null)
+ throw error(className + ": unexpected object " + obj.getClass().getName() + " (" + obj + ")");
+ else
+ throw error(className + ": unexpected null value");
+ }
+
+ 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));
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ Object obj = in.readObject();
+
+ String className = getClass().getName();
+
+ if (obj != null)
+ throw error(className + ": unexpected object " + obj.getClass().getName() + " (" + obj + ")");
+ else
+ throw error(className + ": unexpected null value");
+ }
+
+ /**
+ * Creates the field array for a class. The default
+ * implementation returns a String[] array.
+ *
+ * @param len number of items in the array
+ * @return the new empty array
+ */
+ public Object []createFields(int len)
+ {
+ return new String[len];
+ }
+
+ /**
+ * Creates a field value class. The default
+ * implementation returns the String.
+ *
+ * @param len number of items in the array
+ * @return the new empty array
+ */
+ public Object createField(String name)
+ {
+ return name;
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ String []fieldNames)
+ throws IOException
+ {
+ return readObject(in, (Object []) fieldNames);
+ }
+
+ /**
+ * Reads an object instance from the input stream
+ */
+ public Object readObject(AbstractHessianInput in,
+ Object []fields)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(toString());
+ }
+
+ protected HessianProtocolException error(String msg)
+ {
+ return new HessianProtocolException(msg);
+ }
+
+ protected String codeName(int ch)
+ {
+ if (ch < 0)
+ return "end of file";
+ else
+ return "0x" + Integer.toHexString(ch & 0xff);
+ }
+
+ /**
+ * The NullDeserializer exists as a marker for the factory classes so
+ * they save a null result.
+ */
+ static final class NullDeserializer extends AbstractDeserializer {
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianInput.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianInput.java
new file mode 100644
index 0000000000..e28f3c1eeb
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianInput.java
@@ -0,0 +1,487 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+
+/**
+ * Abstract base class for Hessian requests. Hessian users should only
+ * need to use the methods in this class.
+ *
+ *
+ * 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;
+ private byte []_buffer;
+
+ /**
+ * 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
+ *
+ *
+ * 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.
+ *
+ *
+ * c major minor
+ * m b16 b8 method
+ *
+ */
+ abstract public void startCall()
+ throws IOException;
+
+ /**
+ * Completes reading the call
+ *
+ *
+ * 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
+ *
+ *
+ * r
+ * v
+ *
+ */
+ abstract public void startReply()
+ throws Throwable;
+
+ /**
+ * Starts reading the body of the reply, i.e. after the 'r' has been
+ * parsed.
+ */
+ public void startReplyBody()
+ throws Throwable
+ {
+ }
+
+ /**
+ * Completes reading the call
+ *
+ *
+ * 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 data to an output stream.
+ *
+ *
+ * b b16 b8 non-final binary chunk
+ * B b16 b8 final binary chunk
+ *
+ */
+ public boolean readToOutputStream(OutputStream os)
+ throws IOException
+ {
+ InputStream is = readInputStream();
+
+ if (is == null)
+ return false;
+
+ if (_buffer == null)
+ _buffer = new byte[256];
+
+ try {
+ int len;
+
+ while ((len = is.read(_buffer, 0, _buffer.length)) > 0) {
+ os.write(_buffer, 0, len);
+ }
+
+ return true;
+ } finally {
+ is.close();
+ }
+ }
+
+
+
+ /**
+ * 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.
+ *
+ *
+ */
+ abstract public Object readRemote()
+ throws IOException;
+
+ /**
+ * Reads a reference
+ *
+ *
+ * 'r' 't' b16 b8 type url
+ *
+ * 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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianOutput.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianOutput.java
new file mode 100644
index 0000000000..0e1bcc3ffe
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianOutput.java
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+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
+ private SerializerFactory _defaultSerializerFactory;
+
+ // serializer factory
+ protected SerializerFactory _serializerFactory;
+
+ private byte []_byteBuffer;
+
+ /**
+ * Sets the serializer factory.
+ */
+ public void setSerializerFactory(SerializerFactory factory)
+ {
+ _serializerFactory = factory;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ public SerializerFactory getSerializerFactory()
+ {
+ // the default serializer factory cannot be modified by external
+ // callers
+ if (_serializerFactory == _defaultSerializerFactory) {
+ _serializerFactory = new SerializerFactory();
+ }
+
+ return _serializerFactory;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ protected final SerializerFactory findSerializerFactory()
+ {
+ SerializerFactory factory = _serializerFactory;
+
+ if (factory == null) {
+ factory = SerializerFactory.createDefault();
+ _defaultSerializerFactory = factory;
+ _serializerFactory = factory;
+ }
+
+ 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:
+ *
+ *
+ *
+ * @param method the method name to call.
+ */
+ abstract public void startCall()
+ throws IOException;
+
+ /**
+ * Starts the method call:
+ *
+ *
+ * C
+ *
+ *
+ * @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.
+ *
+ *
+ * C string int
+ *
+ *
+ * @param method the method name to call.
+ */
+ abstract public void writeMethod(String method)
+ throws IOException;
+
+ /**
+ * Completes the method call:
+ *
+ *
+ * string
+ *
+ */
+ abstract public void completeCall()
+ throws IOException;
+
+ /**
+ * Writes a boolean value to the stream. The boolean will be written
+ * with the following syntax:
+ *
+ *
+ *
+ *
+ * @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:
+ *
+ *
+ * T
+ * F
+ *
+ *
+ * @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:
+ *
+ *
+ * I 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:
+ *
+ *
+ * L 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.
+ *
+ *
+ * D 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
+ *
+ *
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * @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.
+ *
+ *
+ * N
+ *
+ *
+ * @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 full output stream.
+ */
+ public void writeByteStream(InputStream is)
+ throws IOException
+ {
+ writeByteBufferStart();
+
+ if (_byteBuffer == null)
+ _byteBuffer = new byte[1024];
+
+ byte []buffer = _byteBuffer;
+
+ int len;
+ while ((len = is.read(buffer, 0, buffer.length)) > 0) {
+ if (len < buffer.length) {
+ int len2 = is.read(buffer, len, buffer.length - len);
+
+ if (len2 < 0) {
+ writeByteBufferEnd(buffer, 0, len);
+ return;
+ }
+
+ len += len2;
+ }
+
+ writeByteBufferPart(buffer, 0, len);
+ }
+
+ writeByteBufferEnd(buffer, 0, 0);
+ }
+
+ /**
+ * Writes a reference.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ *
+ * @param value the integer value to write.
+ */
+ abstract protected void writeRef(int value)
+ throws IOException;
+
+ /**
+ * Removes a reference.
+ */
+ @Deprecated
+ public boolean removeRef(Object obj)
+ throws IOException
+ {
+ return false;
+ }
+
+ /**
+ * 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.
+ *
+ *
+ * Q int
+ *
+ *
+ * @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
+ *
+ * R b32 b24 b16 b8
+ *
writeListBegin
followed by the list contents and then
+ * call writeListEnd
.
+ *
+ *
+ */
+ 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
+ *
+ * V
+ * x13 java.util.ArrayList # type
+ * x93 # length=3
+ * x91 # 1
+ * x92 # 2
+ * x93 # 3
+ * </list>
+ *
writeMapBegin
followed by the map contents and then
+ * call writeMapEnd
.
+ *
+ *
+ */
+ 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
+ *
+ * M type (
writeObjectBegin
followed by the map contents and then
+ * call writeObjectEnd
.
+ *
+ *
+ *
+ * @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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianResolver.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractHessianResolver.java
new file mode 100644
index 0000000000..9872559d02
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractListDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractListDeserializer.java
new file mode 100644
index 0000000000..73a636e78d
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractMapDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractMapDeserializer.java
new file mode 100644
index 0000000000..2d2a2a8ed7
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractSerializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractSerializer.java
new file mode 100644
index 0000000000..92fe417f73
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractSerializer.java
@@ -0,0 +1,151 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import com.caucho.hessian4.HessianException;
+
+/**
+ * Serializing an object.
+ */
+abstract public class AbstractSerializer implements Serializer {
+ public static final NullSerializer NULL = new NullSerializer();
+
+ protected static final Logger log
+ = Logger.getLogger(AbstractSerializer.class.getName());
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ try {
+ Object replace = writeReplace(obj);
+
+ if (replace != null) {
+ // out.removeRef(obj);
+
+ out.writeObject(replace);
+
+ out.replaceRef(replace, obj);
+
+ return;
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ // log.log(Level.FINE, e.toString(), e);
+ throw new HessianException(e);
+ }
+
+ Class> cl = getClass(obj);
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ writeObject10(obj, out);
+ }
+ else {
+ if (ref == -1) {
+ writeDefinition20(cl, out);
+
+ out.writeObjectBegin(cl.getName());
+ }
+
+ writeInstance(obj, out);
+ }
+ }
+
+ protected Object writeReplace(Object obj)
+ {
+ return null;
+ }
+
+ protected Class> getClass(Object obj)
+ {
+ return obj.getClass();
+ }
+
+ protected void writeObject10(Object obj,
+ AbstractHessianOutput out)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ protected void writeDefinition20(Class> cl,
+ AbstractHessianOutput out)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ protected void writeInstance(Object obj,
+ AbstractHessianOutput out)
+ throws IOException
+ {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ /**
+ * The NullSerializer exists as a marker for the factory classes so
+ * they save a null result.
+ */
+ static final class NullSerializer extends AbstractSerializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ throw new IllegalStateException(getClass().getName());
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractSerializerFactory.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractSerializerFactory.java
new file mode 100644
index 0000000000..71a64c5576
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStreamDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStreamDeserializer.java
new file mode 100644
index 0000000000..9cd5faf070
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStreamDeserializer.java
@@ -0,0 +1,100 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializing a byte stream
+ */
+abstract public class AbstractStreamDeserializer extends AbstractDeserializer {
+ abstract public Class getType();
+
+ /**
+ * Reads the Hessian 1.0 style map.
+ */
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ Object value = null;
+
+ while (! in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ value = readStreamValue(in);
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ return value;
+ }
+
+ public Object readObject(AbstractHessianInput in, Object []fields)
+ throws IOException
+ {
+ String []fieldNames = (String []) fields;
+
+ Object value = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i]))
+ value = readStreamValue(in);
+ else
+ in.readObject();
+ }
+
+ return value;
+ }
+
+ abstract protected Object readStreamValue(AbstractHessianInput in)
+ throws IOException;
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStreamSerializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStreamSerializer.java
new file mode 100644
index 0000000000..262a1734ba
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStreamSerializer.java
@@ -0,0 +1,112 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Serializing an object containing a byte stream.
+ */
+abstract public class AbstractStreamSerializer extends AbstractSerializer
+{
+ /**
+ * Writes the object to the output stream.
+ */
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException
+ {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ int ref = out.writeObjectBegin(getClassName(obj));
+
+ if (ref < -1) {
+ out.writeString("value");
+
+ InputStream is = getInputStream(obj);
+ try {
+ out.writeByteStream(is);
+ } finally {
+ is.close();
+ }
+
+ out.writeMapEnd();
+ }
+ else {
+ if (ref == -1) {
+ out.writeClassFieldLength(1);
+ out.writeString("value");
+
+ out.writeObjectBegin(getClassName(obj));
+ }
+
+ InputStream is = getInputStream(obj);
+
+ try {
+ if (is != null)
+ out.writeByteStream(is);
+ else
+ out.writeNull();
+ } finally {
+ if (is != null)
+ is.close();
+ }
+ }
+ }
+
+ protected String getClassName(Object obj)
+ {
+ return obj.getClass().getName();
+ }
+
+ abstract protected InputStream getInputStream(Object obj)
+ throws IOException;
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStringValueDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStringValueDeserializer.java
new file mode 100644
index 0000000000..dbd079dd66
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AbstractStringValueDeserializer.java
@@ -0,0 +1,107 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializes a string-valued object like BigDecimal.
+ */
+abstract public class AbstractStringValueDeserializer
+ extends AbstractDeserializer
+{
+ abstract protected Object create(String value)
+ throws IOException;
+
+ @Override
+ 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;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, Object []fields)
+ throws IOException
+ {
+ String []fieldNames = (String []) fields;
+
+ 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;
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AnnotationDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AnnotationDeserializer.java
new file mode 100644
index 0000000000..b9b961e42e
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/AnnotationDeserializer.java
@@ -0,0 +1,132 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+import com.caucho.hessian4.HessianException;
+
+/**
+ * Deserializing a java annotation for known object types.
+ */
+public class AnnotationDeserializer extends AbstractMapDeserializer {
+ private static final Logger log
+ = Logger.getLogger(AnnotationDeserializer.class.getName());
+
+ private Class _annType;
+
+ public AnnotationDeserializer(Class annType)
+ {
+ _annType = annType;
+ }
+
+ public Class getType()
+ {
+ return _annType;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException
+ {
+ try {
+ int ref = in.addRef(null);
+
+ HashMap
+ * C type int
+ * 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 int END_OF_DATA = -2;
+
+ private static Field _detailMessageField;
+
+ private static final int SIZE = 1024*1024;
+ private static final int GAP = 16;
+
+ // standard, unmodified factory for deserializing objects
+ protected SerializerFactory _defaultSerializerFactory;
+ // factory for deserializing objects in the input stream
+ protected SerializerFactory _serializerFactory;
+
+ private static boolean _isCloseStreamOnClose;
+
+ protected ArrayList
+ * 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
+ *
+ *
+ * Z
+ *
+ */
+ public void completeEnvelope()
+ throws IOException
+ {
+ int tag = read();
+
+ if (tag != 'Z')
+ error("expected end of envelope at " + codeName(tag));
+ }
+
+ /**
+ * Starts reading the call
+ *
+ *
+ * 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.
+ *
+ *
+ * c major minor
+ * m b16 b8 method
+ *
+ */
+ public void startCall()
+ throws IOException
+ {
+ readCall();
+
+ readMethod();
+ }
+
+ public Object []readArguments()
+ throws IOException
+ {
+ int len = readInt();
+
+ Object []args = new Object[len];
+
+ for (int i = 0; i < len; i++)
+ args[i] = readObject();
+
+ return args;
+ }
+
+ /**
+ * Completes reading the call
+ *
+ *
+ *
+ */
+ 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
+ *
+ *
+ * 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
+ *
+ *
+ * z
+ *
+ */
+ public void completeReply()
+ throws IOException
+ {
+ }
+
+ /**
+ * Completes reading the call
+ *
+ *
+ * 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 a packet
+ *
+ *
+ * p major minor
+ *
+ */
+ public int startMessage()
+ throws IOException
+ {
+ int tag = read();
+
+ if (tag == 'p') {
+ } else if (tag == 'P') {
+ } else
+ throw error("expected Hessian message ('p') at " + codeName(tag));
+
+ int major = read();
+ int minor = read();
+
+ return (major << 16) + minor;
+ }
+
+ /**
+ * Completes reading the message
+ *
+ *
+ * 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;
+
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x30) * 256 + read();
+ 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;
+
+ 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;
+
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x30) * 256 + 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 BC_BINARY:
+ case BC_BINARY_CHUNK:
+ _isLastChunk = tag == BC_BINARY;
+ _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 offset = 0;
+ while (offset < _chunkLength) {
+ int sublen = read(buffer, 0, _chunkLength - offset);
+
+ if (sublen <= 0)
+ break;
+
+ offset += sublen;
+ }
+
+ return buffer;
+ }
+
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+
+ byte []buffer = new byte[_chunkLength];
+
+ int offset = 0;
+ while (offset < _chunkLength) {
+ int sublen = read(buffer, 0, _chunkLength - offset);
+
+ if (sublen <= 0)
+ break;
+
+ offset += sublen;
+ }
+
+ 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;
+ }
+
+ 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;
+
+ int value = parseByte();
+
+ // special code so successive read byte won't
+ // be read as a single object.
+ if (_chunkLength == 0)
+ _chunkLength = END_OF_DATA;
+
+ return value;
+ }
+
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+
+ int value = parseByte();
+
+ // special code so successive read byte won't
+ // be read as a single object.
+ if (_chunkLength == 0)
+ _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;
+
+ 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;
+ }
+
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + 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 = _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 = _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(type, 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.size() <= ref)
+ throw error("No classes defined at reference '"
+ + Integer.toHexString(tag) + "'");
+
+ ObjectDefinition def = _classDefs.get(ref);
+
+ return readObjectInstance(null, def);
+ }
+
+ case 'O':
+ {
+ int ref = readInt();
+
+ if (_classDefs.size() <= ref)
+ throw error("Illegal object reference #" + ref);
+
+ ObjectDefinition def = _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();
+
+ SerializerFactory factory = findSerializerFactory();
+
+ Deserializer reader = factory.getObjectDeserializer(type, null);
+
+ Object []fields = reader.createFields(len);
+ String []fieldNames = new String[len];
+
+ for (int i = 0; i < len; i++) {
+ String name = readString();
+
+ fields[i] = reader.createField(name);
+ fieldNames[i] = name;
+ }
+
+ ObjectDefinition def
+ = new ObjectDefinition(type, reader, fields, fieldNames);
+
+ _classDefs.add(def);
+ }
+
+ private Object readObjectInstance(Class> cl,
+ ObjectDefinition def)
+ throws IOException
+ {
+ String type = def.getType();
+ Deserializer reader = def.getReader();
+ Object []fields = def.getFields();
+
+ SerializerFactory factory = findSerializerFactory();
+
+ if (cl != reader.getType() && cl != null) {
+ reader = factory.getObjectDeserializer(type, cl);
+
+ return reader.readObject(this, def.getFieldNames());
+ }
+ else {
+ return reader.readObject(this, fields);
+ }
+ }
+
+ /**
+ * 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()
+ {
+ _refs.clear();
+ }
+
+ public void reset()
+ {
+ resetReferences();
+
+ _classDefs.clear();
+ _types.clear();
+ }
+
+ public void resetBuffer()
+ {
+ int offset = _offset;
+ _offset = 0;
+
+ int length = _length;
+ _length = 0;
+
+ if (length > 0 && offset != length)
+ throw new IllegalStateException("offset=" + offset + " length=" + length);
+ }
+
+ 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.
+ *
+ *
+ * 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;
+
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (code - 0x30) * 256 + 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 BC_BINARY:
+ case BC_BINARY_CHUNK:
+ _isLastChunk = tag == BC_BINARY;
+ _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;
+
+ case 0x34: case 0x35: case 0x36: case 0x37:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+ 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 BC_BINARY_CHUNK:
+ _isLastChunk = false;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case BC_BINARY:
+ _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);
+ }
+ }
+
+ 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;
+ }
+
+ protected void unread()
+ {
+ if (_offset <= 0)
+ throw new IllegalStateException();
+
+ _offset--;
+ }
+
+ 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 = 0;
+ if (_is != null)
+ 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 {
+ int offset = _offset;
+ String context
+ = buildDebugContext(_buffer, 0, _length, offset);
+
+ Object obj = readObject();
+
+ if (obj != null) {
+ return error("expected " + expect
+ + " at 0x" + Integer.toHexString(ch & 0xff)
+ + " " + obj.getClass().getName() + " (" + obj + ")"
+ + "\n " + context + "");
+ }
+ else
+ return error("expected " + expect
+ + " at 0x" + Integer.toHexString(ch & 0xff) + " null");
+ } catch (Exception e) {
+ log.log(Level.FINE, e.toString(), e);
+
+ return error("expected " + expect
+ + " at 0x" + Integer.toHexString(ch & 0xff));
+ }
+ }
+ }
+
+ private String buildDebugContext(byte []buffer, int offset, int length,
+ int errorOffset)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("[");
+ for (int i = 0; i < errorOffset; i++) {
+ int ch = buffer[offset + i];
+ addDebugChar(sb, ch);
+ }
+ sb.append("] ");
+ addDebugChar(sb, buffer[offset + errorOffset]);
+ sb.append(" [");
+ for (int i = errorOffset + 1; i < length; i++) {
+ int ch = buffer[offset + i];
+ addDebugChar(sb, ch);
+ }
+ sb.append("]");
+
+ return sb.toString();
+ }
+
+ private void addDebugChar(StringBuilder sb, int ch)
+ {
+ if (ch >= 0x20 && ch < 0x7f) {
+ sb.append((char) ch);
+ }
+ else if (ch == '\n')
+ sb.append((char) ch);
+ else
+ sb.append(String.format("\\x%02x", 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 Deserializer _reader;
+ private final Object []_fields;
+ private final String []_fieldNames;
+
+ ObjectDefinition(String type,
+ Deserializer reader,
+ Object []fields,
+ String []fieldNames)
+ {
+ _type = type;
+ _reader = reader;
+ _fields = fields;
+ _fieldNames = fieldNames;
+ }
+
+ String getType()
+ {
+ return _type;
+ }
+
+ Deserializer getReader()
+ {
+ return _reader;
+ }
+
+ Object []getFields()
+ {
+ return _fields;
+ }
+
+ String []getFieldNames()
+ {
+ return _fieldNames;
+ }
+ }
+
+ static {
+ try {
+ _detailMessageField = Throwable.class.getDeclaredField("detailMessage");
+ _detailMessageField.setAccessible(true);
+ } catch (Throwable e) {
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/Hessian2Output.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/Hessian2Output.java
new file mode 100644
index 0000000000..c9fc90ec1c
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/Hessian2Output.java
@@ -0,0 +1,1733 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+import org.jboss.netty.channel.ChannelFuture;
+
+import com.caucho.hessian4.util.IdentityIntMap;
+
+/**
+ * Output stream for Hessian 2 requests.
+ *
+ *
+ * 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
+{
+ public final static int SIZE = 1024*1024;
+
+ // the output stream/
+ protected OutputStream _os;
+
+ // map of references
+ private final IdentityIntMap _refs
+ = new IdentityIntMap(256);
+
+ private boolean _isCloseStreamOnClose;
+
+ // map of classes
+ private final IdentityIntMap _classRefs
+ = new IdentityIntMap(256);
+
+ // map of types
+ private HashMapstartCall
+ * instead of call
if they wanted finer control over
+ * writing the arguments, or needed to write headers.
+ *
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startCall(String method, int length)
+ throws IOException
+ {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ flushBuffer();
+ 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
+ * string # method name
+ * int # arg count
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startCall()
+ throws IOException
+ {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'C';
+ }
+
+ /**
+ * Starts an envelope.
+ *
+ *
+ * C
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void startEnvelope(String method)
+ throws IOException
+ {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ flushBuffer();
+ offset = _offset;
+ }
+
+ _buffer[_offset++] = (byte) 'E';
+
+ writeString(method);
+ }
+
+ /**
+ * Completes an envelope.
+ *
+ *
+ * E major minor
+ * m b16 b8 method-name
+ *
+ * Z
+ *
+ */
+ public void completeEnvelope()
+ throws IOException
+ {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'Z';
+ }
+
+ /**
+ * Writes the method tag.
+ *
+ *
+ *
+ * @param method the method name to call.
+ */
+ public void writeMethod(String method)
+ throws IOException
+ {
+ writeString(method);
+ }
+
+ /**
+ * Completes.
+ *
+ *
+ * string
+ *
+ */
+ public void completeCall()
+ throws IOException
+ {
+ /*
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'Z';
+ */
+ }
+
+ /**
+ * Starts the reply
+ *
+ *
+ * z
+ *
+ * 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
+ *
+ *
+ * z
+ *
+ */
+ public void completeReply()
+ throws IOException
+ {
+ }
+
+ /**
+ * Starts a packet
+ *
+ *
+ * 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
+ *
+ *
+ * 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
+ *
+ *
+ * @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 Object(), _refs.size(), false);
+
+ 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
+ = findSerializerFactory().getObjectSerializer(object.getClass());
+
+ serializer.writeObject(object, this);
+ }
+
+ /**
+ * Writes the list header to the stream. List writers will call
+ *
+ * F H
+ * \x04code
+ * \x10the fault code
+ *
+ * \x07message
+ * \x11the fault message
+ *
+ * \x06detail
+ * M\xnnjavax.ejb.FinderException
+ * ...
+ * Z
+ * Z
+ *
writeListBegin
followed by the list contents and then
+ * call writeListEnd
.
+ *
+ *
+ *
+ * @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
+ *
+ * list ::= V type value* Z
+ * ::= v type int value*
+ *
writeMapBegin
followed by the map contents and then
+ * call writeMapEnd
.
+ *
+ *
+ */
+ public void writeMapBegin(String type)
+ throws IOException
+ {
+ if (SIZE < _offset + 32)
+ flushBuffer();
+
+ 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)
+ flushBuffer();
+
+ _buffer[_offset++] = (byte) BC_END;
+ }
+
+ /**
+ * Writes the object definition
+ *
+ *
+ * map ::= M type (
+ */
+ @Override
+ public int writeObjectBegin(String type)
+ throws IOException
+ {
+ int newRef = _classRefs.size();
+ int ref = _classRefs.put(type, newRef, false);
+
+ if (newRef != ref) {
+ if (SIZE < _offset + 32)
+ flushBuffer();
+
+ if (ref <= OBJECT_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
+ }
+ else {
+ _buffer[_offset++] = (byte) 'O';
+ writeInt(ref);
+ }
+
+ return ref;
+ }
+ else {
+ if (SIZE < _offset + 32)
+ flushBuffer();
+
+ _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
+ {
+ }
+
+ /**
+ *
+ * C <string> <int> <string>*
+ *
+ */
+ 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
+ * type ::= string
+ * ::= int
+ *
+ *
+ * @param value the boolean value to write.
+ */
+ public void writeBoolean(boolean value)
+ throws IOException
+ {
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ 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:
+ *
+ *
+ * T
+ * F
+ *
+ *
+ * @param value the integer value to write.
+ */
+ public void writeInt(int value)
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flushBuffer();
+ 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:
+ *
+ *
+ * I 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) {
+ flushBuffer();
+ 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:
+ *
+ *
+ * L 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) {
+ flushBuffer();
+ 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.
+ *
+ *
+ * D 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
+ {
+ if (SIZE < _offset + 32)
+ flushBuffer();
+
+ 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
+ *
+ *
+ * date ::= d b7 b6 b5 b4 b3 b2 b1 b0
+ * ::= x65 b3 b2 b1 b0
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeNull()
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flushBuffer();
+ 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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeString(String value)
+ throws IOException
+ {
+ int offset = _offset;
+ byte []buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flushBuffer();
+ 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) {
+ flushBuffer();
+ 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) {
+ flushBuffer();
+ 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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * @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)
+ flushBuffer();
+
+ _buffer[_offset++] = (byte) ('N');
+ }
+ else {
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ // 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)
+ flushBuffer();
+
+ 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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * @param value the string value to write.
+ */
+ public void writeBytes(byte []buffer)
+ throws IOException
+ {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ _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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * @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 {
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ if (SIZE < _offset + 3)
+ flushBuffer();
+
+ _buffer[_offset++] = (byte) BC_BINARY_CHUNK;
+ _buffer[_offset++] = (byte) (sublen >> 8);
+ _buffer[_offset++] = (byte) sublen;
+
+ if (SIZE < _offset + sublen)
+ flushBuffer();
+
+ System.arraycopy(buffer, offset, _buffer, _offset, sublen);
+ _offset += sublen;
+
+ length -= sublen;
+ offset += sublen;
+
+ }
+
+ /*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);
+ }
+
+ if (SIZE < _offset + length)
+ flushBuffer();
+ System.arraycopy(buffer, offset, _buffer, _offset, length);
+
+ _offset += length;
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ * N
+ *
+ */
+ public void writeByteBufferStart()
+ throws IOException
+ {
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ *
+ */
+ public void writeByteBufferPart(byte []buffer, int offset, int length)
+ throws IOException
+ {
+ while (length > 0) {
+ flushIfFull();
+
+ int sublen = _buffer.length - _offset;
+
+ if (length < sublen)
+ sublen = length;
+
+ _buffer[_offset++] = 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;
+ }
+ }
+
+ /**
+ * 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 full output stream.
+ */
+ @Override
+ public void writeByteStream(InputStream is)
+ throws IOException
+ {
+ while (true) {
+ int len = SIZE - _offset - 3;
+
+ if (len < 16) {
+ flushBuffer();
+ len = SIZE - _offset - 3;
+ }
+
+ len = is.read(_buffer, _offset + 3, len);
+
+ if (len <= 0) {
+ _buffer[_offset++] = BC_BINARY_DIRECT;
+ return;
+ }
+
+ _buffer[_offset + 0] = (byte) BC_BINARY_CHUNK;
+ _buffer[_offset + 1] = (byte) (len >> 8);
+ _buffer[_offset + 2] = (byte) (len);
+
+ _offset += len + 3;
+ }
+ }
+
+ /**
+ * Writes a reference.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ *
+ * @param value the integer value to write.
+ */
+ @Override
+ protected void writeRef(int value)
+ throws IOException
+ {
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ _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 newRef = _refs.size();
+
+ int ref = _refs.put(object, newRef, false);
+
+ if (ref != newRef) {
+ writeRef(ref);
+
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ /**
+ * Removes a reference.
+ */
+ /*
+ private boolean removeRef(Object obj)
+ throws IOException
+ {
+ if (_refs != null) {
+ _refs.put(obj, -1);
+
+ return true;
+ }
+ else
+ return false;
+ }
+ */
+
+ /**
+ * Replaces a reference from one object to another.
+ */
+ public boolean replaceRef(Object oldRef, Object newRef)
+ throws IOException
+ {
+ int value = _refs.get(oldRef);
+
+ if (value >= 0) {
+ _refs.put(newRef, value, true);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Starts the streaming message
+ *
+ *
+ * x51 <int>
+ *
+ * P x02 x00
+ *
+ */
+ public void writeStreamingObject(Object obj)
+ throws IOException
+ {
+ startPacket();
+
+ writeObject(obj);
+
+ endPacket();
+ }
+
+ /**
+ * Starts a streaming packet
+ *
+ *
+ * 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
+ *
+ *
+ * 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.
+ *
+ *
+ * c major minor
+ * m b16 b8 method
+ *
+ */
+ public void startCall()
+ throws IOException
+ {
+ readCall();
+
+ while (readHeader() != null) {
+ readObject();
+ }
+
+ readMethod();
+ }
+
+ /**
+ * Completes reading the call
+ *
+ *
+ * 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
+ *
+ *
+ * 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();
+
+ startReplyBody();
+ }
+
+ public void startReplyBody()
+ throws Throwable
+ {
+ int 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
+ *
+ *
+ * z
+ *
+ */
+ public void completeReply()
+ throws IOException
+ {
+ int tag = read();
+
+ if (tag != 'z')
+ error("expected end of reply at " + codeName(tag));
+ }
+
+ /**
+ * Completes reading the call
+ *
+ *
+ * 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);
+
+ 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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianInputFactory.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianInputFactory.java
new file mode 100644
index 0000000000..918c7efbfe
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianInputFactory.java
@@ -0,0 +1,174 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Logger;
+
+public class HessianInputFactory
+{
+ public static final Logger log
+ = Logger.getLogger(HessianInputFactory.class.getName());
+
+ private HessianFactory _factory = new HessianFactory();
+
+ public void setSerializerFactory(SerializerFactory factory)
+ {
+ _factory.setSerializerFactory(factory);
+ }
+
+ public SerializerFactory getSerializerFactory()
+ {
+ return _factory.getSerializerFactory();
+ }
+
+ public HeaderType readHeader(InputStream is)
+ throws IOException
+ {
+ int code = is.read();
+
+ int major = is.read();
+ int minor = is.read();
+
+ switch (code) {
+ case -1:
+ throw new IOException("Unexpected end of file for Hessian message");
+
+ case 'c':
+ if (major >= 2)
+ return HeaderType.CALL_1_REPLY_2;
+ else
+ return HeaderType.CALL_1_REPLY_1;
+ case 'r':
+ return HeaderType.REPLY_1;
+
+ case 'H':
+ return HeaderType.HESSIAN_2;
+
+ default:
+ throw new IOException((char) code + " 0x" + Integer.toHexString(code) + " is an unknown Hessian message code.");
+ }
+ }
+
+ 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) {
+ return _factory.createHessian2Input(is);
+ }
+ else {
+ return _factory.createHessianInput(is);
+ }
+
+ default:
+ throw new IOException((char) code + " is an unknown Hessian message code.");
+ }
+ }
+
+ public enum HeaderType {
+ CALL_1_REPLY_1,
+ CALL_1_REPLY_2,
+ HESSIAN_2,
+ REPLY_1,
+ REPLY_2;
+
+ public boolean isCall1()
+ {
+ switch (this) {
+ case CALL_1_REPLY_1:
+ case CALL_1_REPLY_2:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isCall2()
+ {
+ switch (this) {
+ case HESSIAN_2:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isReply1()
+ {
+ switch (this) {
+ case CALL_1_REPLY_1:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isReply2()
+ {
+ switch (this) {
+ case CALL_1_REPLY_2:
+ case HESSIAN_2:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianMethodSerializationException.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianMethodSerializationException.java
new file mode 100644
index 0000000000..41e14a9442
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianMethodSerializationException.java
@@ -0,0 +1,88 @@
+/*
+ * 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.caucho.hessian4.io;
+
+import com.caucho.hessian4.HessianException;
+
+/**
+ * Exception for faults when the fault doesn't return a java exception.
+ * This exception is required for MicroHessianInput.
+ */
+public class HessianMethodSerializationException extends HessianException {
+ /**
+ * Zero-arg constructor.
+ */
+ public HessianMethodSerializationException()
+ {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianMethodSerializationException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianMethodSerializationException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianMethodSerializationException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianOutput.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianOutput.java
new file mode 100644
index 0000000000..b7922e37e5
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianOutput.java
@@ -0,0 +1,956 @@
+/*
+ * 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.caucho.hessian4.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.
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ * @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
+ * m b16 b8 method-name
+ *
+ *
+ * @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.
+ *
+ *
+ * c major minor
+ *
+ *
+ * @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.
+ *
+ *
+ * m b16 b8 method-name
+ *
+ */
+ public void completeCall()
+ throws IOException
+ {
+ os.write('z');
+ }
+
+ /**
+ * Starts the reply
+ *
+ *
+ * z
+ *
+ * r
+ *
+ */
+ public void startReply()
+ throws IOException
+ {
+ os.write('r');
+ os.write(1);
+ os.write(0);
+ }
+
+ /**
+ * Completes reading the reply
+ *
+ *
+ * z
+ *
+ */
+ public void completeReply()
+ throws IOException
+ {
+ os.write('z');
+ }
+
+ /**
+ * Writes a header name. The header value must immediately follow.
+ *
+ *
+ */
+ 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:
+ *
+ *
+ * H b16 b8 foo value
+ *
+ *
+ * @param code the fault code, a three digit
+ */
+ public void writeFault(String code, String message, Object detail)
+ throws IOException
+ {
+ // hessian/3525
+ os.write('r');
+ os.write(1);
+ os.write(0);
+
+ os.write('f');
+ writeString("code");
+ writeString(code);
+
+ writeString("message");
+ writeString(message);
+
+ if (detail != null) {
+ writeString("detail");
+ writeObject(detail);
+ }
+ os.write('z');
+
+ 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
+ *
+ * f
+ * <string>code
+ * <string>the fault code
+ *
+ * <string>message
+ * <string>the fault mesage
+ *
+ * <string>detail
+ * mt\x00\xnnjavax.ejb.FinderException
+ * ...
+ * z
+ * z
+ *
writeListBegin
followed by the list contents and then
+ * call writeListEnd
.
+ *
+ *
+ */
+ 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
+ *
+ * V
+ * t b16 b8 type
+ * l b32 b24 b16 b8
+ *
writeMapBegin
followed by the map contents and then
+ * call writeMapEnd
.
+ *
+ *
+ */
+ 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.
+ *
+ *
+ * Mt b16 b8 (
+ */
+ 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:
+ *
+ *
+ * 'r' 't' b16 b8 type url
+ *
+ *
+ * @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:
+ *
+ *
+ * T
+ * F
+ *
+ *
+ * @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:
+ *
+ *
+ * I 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:
+ *
+ *
+ * L 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.
+ *
+ *
+ * D 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
+ *
+ *
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * S b16 b8 string-value
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * @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:
+ *
+ *
+ * N
+ *
+ *
+ * If the value is null, it will be written as
+ *
+ *
+ * B b16 b18 bytes
+ *
+ *
+ * @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.
+ *
+ *
+ * N
+ *
+ */
+ public void writeByteBufferStart()
+ throws IOException
+ {
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ *
+ *
+ *
+ */
+ 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.
+ *
+ *
+ * b b16 b18 bytes
+ *
+ *
+ * @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.
+ *
+ *
+ * R b32 b24 b16 b8
+ *
+ */
+ 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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianProtocolException.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianProtocolException.java
new file mode 100644
index 0000000000..9a0a3f80ac
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianRemote.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianRemote.java
new file mode 100644
index 0000000000..c8e3cb493b
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.io;
+
+/**
+ * Encapsulates a remote address when no stub is available, e.g. for
+ * Java MicroEdition.
+ */
+public class HessianRemote implements java.io.Serializable {
+ 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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianRemoteObject.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianRemoteObject.java
new file mode 100644
index 0000000000..84acae53df
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.io;
+
+/**
+ * Interface for any hessian remote object.
+ */
+public interface HessianRemoteObject {
+ public String getHessianType();
+ public String getHessianURL();
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianRemoteResolver.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianRemoteResolver.java
new file mode 100644
index 0000000000..4c774854cd
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianSerializerInput.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianSerializerInput.java
new file mode 100644
index 0000000000..161d89b5fb
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianSerializerInput.java
@@ -0,0 +1,184 @@
+/*
+ * 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.caucho.hessian4.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.
+ *
+ *
+ * P
+ *
Serialization
+ *
+ *
+ * InputStream is = new FileInputStream("test.xml");
+ * HessianOutput in = new HessianSerializerOutput(is);
+ *
+ * Object obj = in.readObject();
+ * is.close();
+ *
+ *
+ * Parsing a Hessian reply
+ *
+ *
+ * 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 Hessian2Input {
+ /**
+ * 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()
+ {
+ super(null);
+ }
+
+ /**
+ * 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()) {
+ unread();
+
+ 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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianSerializerOutput.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianSerializerOutput.java
new file mode 100644
index 0000000000..1b8b9b8d4f
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianSerializerOutput.java
@@ -0,0 +1,147 @@
+/*
+ * 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.caucho.hessian4.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.
+ *
+ * Serialization
+ *
+ *
+ * OutputStream os = new FileOutputStream("test.xml");
+ * HessianOutput out = new HessianSerializerOutput(os);
+ *
+ * out.writeObject(obj);
+ * os.close();
+ *
+ *
+ * Writing an RPC Call
+ *
+ *
+ * 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 Hessian2Output {
+ /**
+ * 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()
+ {
+ super(null);
+ }
+
+ /**
+ * 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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianServiceException.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/HessianServiceException.java
new file mode 100644
index 0000000000..432aded172
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/IOExceptionWrapper.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/IOExceptionWrapper.java
new file mode 100644
index 0000000000..f2671987a6
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/InputStreamDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/InputStreamDeserializer.java
new file mode 100644
index 0000000000..f2679c11f5
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/InputStreamDeserializer.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 "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.caucho.hessian4.io;
+
+import java.io.IOException;
+
+/**
+ * Serializing a stream object.
+ */
+public class InputStreamDeserializer extends AbstractDeserializer {
+ public static final InputStreamDeserializer DESER
+ = new InputStreamDeserializer();
+
+ public InputStreamDeserializer()
+ {
+ }
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException
+ {
+ return in.readInputStream();
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/InputStreamSerializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/InputStreamSerializer.java
new file mode 100644
index 0000000000..a82e3c850a
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/InputStreamSerializer.java
@@ -0,0 +1,73 @@
+/*
+ * 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.caucho.hessian4.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 {
+ out.writeByteStream(is);
+ }
+ }
+}
diff --git a/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/IteratorSerializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/IteratorSerializer.java
new file mode 100644
index 0000000000..ce548b9132
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/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.caucho.hessian4.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/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/JavaDeserializer.java b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/JavaDeserializer.java
new file mode 100644
index 0000000000..8c3fd87125
--- /dev/null
+++ b/javaUtilities/yajsw/src/hessian/com/caucho/hessian4/io/JavaDeserializer.java
@@ -0,0 +1,753 @@
+/*
+ * 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.caucho.hessian4.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;
+
+
+/**
+ * Serializing an object for known object types.
+ */
+public class JavaDeserializer extends AbstractMapDeserializer {
+ private Class> _type;
+ private HashMap,FieldDeserializer> _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]);
+ }
+ }
+ }
+
+ @Override
+ public Class> getType()
+ {
+ return _type;
+ }
+
+ @Override
+ public boolean isReadResolve()
+ {
+ return _readResolve != null;
+ }
+
+ 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);
+ }
+ }
+
+ @Override
+ public Object []createFields(int len)
+ {
+ return new FieldDeserializer[len];
+ }
+
+ public Object createField(String name)
+ {
+ Object reader = _fieldMap.get(name);
+
+ if (reader == null)
+ reader = NullFieldDeserializer.DESER;
+
+ return reader;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ Object []fields)
+ throws IOException
+ {
+ try {
+ Object obj = instantiate();
+
+ return readObject(in, obj, (FieldDeserializer []) fields);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ 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 = _fieldMap.get(key);
+
+ if (deser != null)
+ deser.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object resolve = resolve(in, obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ private Object readObject(AbstractHessianInput in,
+ Object obj,
+ FieldDeserializer []fields)
+ throws IOException
+ {
+ try {
+ int ref = in.addRef(obj);
+
+ for (FieldDeserializer reader : fields) {
+ reader.deserialize(in, obj);
+ }
+
+ Object resolve = resolve(in, 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);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ Object obj,
+ String []fieldNames)
+ throws IOException
+ {
+ try {
+ int ref = in.addRef(obj);
+
+ for (String fieldName : fieldNames) {
+ FieldDeserializer reader = _fieldMap.get(fieldName);
+
+ if (reader != null)
+ reader.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ Object resolve = resolve(in, 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);
+ }
+ }
+
+ protected Object resolve(AbstractHessianInput in, 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.getCause() instanceof Exception)
+ throw (Exception) e.getCause();
+ else
+ 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