/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* Licensed Materials - Property of IBM
* RMI-IIOP v1.0
* Copyright IBM Corp. 1998 1999 All Rights Reserved
*
*/
package org.jboss.com.sun.corba.se.impl.encoding;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.rmi.CORBA.Tie;
import javax.rmi.CORBA.ValueHandler;
import org.jboss.com.sun.corba.se.impl.corba.CORBAObjectImpl;
import org.jboss.com.sun.corba.se.impl.corba.PrincipalImpl;
import org.jboss.com.sun.corba.se.impl.corba.TypeCodeImpl;
import org.jboss.com.sun.corba.se.impl.logging.OMGSystemException;
import org.jboss.com.sun.corba.se.impl.logging.ORBUtilSystemException;
import org.jboss.com.sun.corba.se.impl.orbutil.CacheTable;
import org.jboss.com.sun.corba.se.impl.orbutil.ORBUtility;
import org.jboss.com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
import org.jboss.com.sun.corba.se.impl.orbutil.RepositoryIdInterface;
import org.jboss.com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
import org.jboss.com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
import org.jboss.com.sun.corba.se.impl.util.RepositoryId;
import org.jboss.com.sun.corba.se.impl.util.Utility;
import org.jboss.com.sun.corba.se.pept.protocol.MessageMediator;
import org.jboss.com.sun.corba.se.pept.transport.ByteBufferPool;
import org.jboss.com.sun.corba.se.spi.ior.IOR;
import org.jboss.com.sun.corba.se.spi.ior.IORFactories;
import org.jboss.com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import org.jboss.com.sun.corba.se.spi.logging.CORBALogDomains;
import org.jboss.com.sun.corba.se.spi.orb.ORB;
import org.jboss.com.sun.corba.se.spi.orb.ORBVersionFactory;
import org.jboss.com.sun.corba.se.spi.presentation.rmi.PresentationDefaults;
import org.jboss.com.sun.corba.se.spi.presentation.rmi.PresentationManager;
import org.jboss.com.sun.corba.se.spi.presentation.rmi.StubAdapter;
import org.jboss.com.sun.corba.se.spi.protocol.CorbaClientDelegate;
import org.jboss.com.sun.org.omg.CORBA.portable.ValueHelper;
import org.jboss.com.sun.org.omg.SendingContext.CodeBase;
import org.omg.CORBA.Any;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.CustomMarshal;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.Principal;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA.portable.CustomValue;
import org.omg.CORBA.portable.IDLEntity;
import org.omg.CORBA.portable.IndirectionException;
import org.omg.CORBA.portable.StreamableValue;
import org.omg.CORBA.portable.ValueBase;
import org.omg.CORBA.portable.ValueFactory;
@SuppressWarnings("deprecation")
public class CDRInputStream_1_0 extends CDRInputStreamBase implements RestorableInputStream
{
private static final String kReadMethod = "read";
private static final int maxBlockLength = 0x7fffff00;
protected BufferManagerRead bufferManagerRead;
protected ByteBufferWithInfo bbwi;
// Set to the ORB's transportDebugFlag value. This value is
// used if the ORB is null.
private boolean debug = false;
protected boolean littleEndian;
protected ORB orb;
protected ORBUtilSystemException wrapper;
protected OMGSystemException omgWrapper;
protected ValueHandler valueHandler = null;
// Value cache
private CacheTable valueCache = null;
// Repository ID cache
private CacheTable repositoryIdCache = null;
// codebase cache
private CacheTable codebaseCache = null;
// Current Class Stack (repository Ids of current class being read) private Stack currentStack = null;
// Length of current chunk, or a large positive number if not in a chunk
protected int blockLength = maxBlockLength;
// Read end flag (value nesting depth)
protected int end_flag = 0;
// Beginning with the resolution to interop issue 3526 (4328?), only enclosing chunked valuetypes are taken into
// account when computing the nesting level. However, we still need the old computation around for interoperability
// with our
// older ORBs.
private int chunkedValueNestingLevel = 0;
// Flag used to determine whether blocksize was zero
// private int checkForNullBlock = -1;
// In block flag
// private boolean inBlock = false;
// Indicates whether we are inside a value
// private boolean outerValueDone = true;
// Int used by read_value(Serializable) that is set by this class
// before calling ValueFactory.read_value
protected int valueIndirection = 0;
// Int set by readStringOrIndirection to communicate the actual
// offset of the string length field back to the caller
protected int stringIndirection = 0;
// Flag indicating whether we are unmarshalling a chunked value
protected boolean isChunked = false;
// Repository ID handlers
private RepositoryIdUtility repIdUtil;
private RepositoryIdStrings repIdStrs;
// Code set converters (created when first needed)
private CodeSetConversion.BTCConverter charConverter;
private CodeSetConversion.BTCConverter wcharConverter;
// RMI-IIOP stream format version 2 case in which we know that there is no more optional data available. If the
// Serializable's readObject method tries to read anything, we must throw a MARSHAL with the special minor code so
// that the ValueHandler can give the correct exception to readObject. The state is cleared when the ValueHandler
// calls end_value after the readObject method exits.
private boolean specialNoOptionalDataState = false;
// Template method
public CDRInputStreamBase dup()
{
CDRInputStreamBase result = null;
try
{
result = this.getClass().newInstance();
}
catch (Exception e)
{
throw wrapper.couldNotDuplicateCdrInputStream(e);
}
result.init(this.orb, this.bbwi.byteBuffer, this.bbwi.buflen, this.littleEndian, this.bufferManagerRead);
((CDRInputStream_1_0) result).bbwi.position(this.bbwi.position());
// To ensure we keep bbwi.byteBuffer.limit in sync with bbwi.buflen.
((CDRInputStream_1_0) result).bbwi.byteBuffer.limit(this.bbwi.buflen);
return result;
}
/**
* NOTE: size passed to init means buffer size
*/
public void init(org.omg.CORBA.ORB orb, ByteBuffer byteBuffer, int size, boolean littleEndian,
BufferManagerRead bufferManager)
{
this.orb = (ORB) orb;
this.wrapper = ORBUtilSystemException.get((ORB) orb, CORBALogDomains.RPC_ENCODING);
this.omgWrapper = OMGSystemException.get((ORB) orb, CORBALogDomains.RPC_ENCODING);
this.littleEndian = littleEndian;
this.bufferManagerRead = bufferManager;
this.bbwi = new ByteBufferWithInfo(orb, byteBuffer, 0);
this.bbwi.buflen = size;
this.bbwi.byteBuffer.limit(bbwi.buflen);
this.markAndResetHandler = bufferManagerRead.getMarkAndResetHandler();
debug = ((ORB) orb).transportDebugFlag;
}
// See description in CDRInputStream
void performORBVersionSpecificInit()
{
createRepositoryIdHandlers();
}
private final void createRepositoryIdHandlers()
{
repIdUtil = RepositoryIdFactory.getRepIdUtility(orb);
repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(orb);
}
public GIOPVersion getGIOPVersion()
{
return GIOPVersion.V1_0;
}
// Called by Request and Reply message. Valid for GIOP versions >= 1.2 only. Illegal for GIOP versions < 1.2.
void setHeaderPadding(boolean headerPadding)
{
throw wrapper.giopVersionError();
}
protected final int computeAlignment(int index, int align)
{
if (align > 1)
{
int incr = index & (align - 1);
if (incr != 0)
return align - incr;
}
return 0;
}
public int getSize()
{
return bbwi.position();
}
protected void checkBlockLength(int align, int dataSize)
{
// Since chunks can end at arbitrary points (though not within primitive CDR types, arrays of primitives,
// strings, wstrings, or indirections), we must check here for termination of the current chunk.
if (!isChunked)
return;
// RMI-IIOP stream format version 2 case in which we know that there is no more optional data available. If the
// Serializable's readObject method tries to read anything, must throw a MARSHAL exception with the special
// minor code so that the ValueHandler can give the correct exception to readObject. The state is cleared when
// the ValueHandler calls end_value after the readObject method exits.
if (specialNoOptionalDataState)
{
throw omgWrapper.rmiiiopOptionalDataIncompatible1();
}
boolean checkForEndTag = false;
// Are we at the end of the current chunk? If so, try to interpret the next long as a chunk length. (It has to
// be either a chunk length, end tag, or valuetag.) If it isn't a chunk length, blockLength will remain set to
// maxBlockLength.
if (blockLength == get_offset())
{
blockLength = maxBlockLength;
start_block();
// What's next is either a valuetag or an end tag. If it's a valuetag, we're probably being called as part
// of the process to read the valuetag. If it's an end tag, then there isn't enough data left in this
// valuetype to read!
if (blockLength == maxBlockLength)
checkForEndTag = true;
}
else if (blockLength < get_offset())
{
// Are we already past the end of the current chunk? This is always an error.
throw wrapper.chunkOverflow();
}
// If what's next on the wire isn't a chunk length or what we want to read (which can't be split across chunks)
// won't fit in the current chunk, throw this exception. This probably means that we're in an
// RMI-IIOPrializable's readObject method or a custom marshaled IDL type is reading too much/in an incorrect
// order
int requiredNumBytes = computeAlignment(bbwi.position(), align) + dataSize;
if (blockLength != maxBlockLength && blockLength < get_offset() + requiredNumBytes)
{
throw omgWrapper.rmiiiopOptionalDataIncompatible2();
}
// REVISIT - We should look at using the built in advancement of using ByteBuffer.get() rather than explicitly
// advancing the ByteBuffer's position. This is true for anywhere we are incrementing the ByteBuffer's position.
if (checkForEndTag)
{
bbwi.position(bbwi.position() - 4);
// It was an end tag, so there wasn't enough data left in the valuetype's encoding on the wire to read what
// we wanted (nextLong < 0)
throw omgWrapper.rmiiiopOptionalDataIncompatible3();
}
}
protected void alignAndCheck(int align, int n)
{
checkBlockLength(align, n);
// WARNING: Must compute real alignment after calling checkBlockLength since it may move the position
int alignResult = computeAlignment(bbwi.position(), align);
bbwi.position(bbwi.position() + alignResult);
if (bbwi.position() + n > bbwi.buflen)
grow(align, n);
}
// This can be overridden....
protected void grow(int align, int n)
{
bbwi.needed = n;
bbwi = bufferManagerRead.underflow(bbwi);
}
// Marshal primitives.
public final void consumeEndian()
{
littleEndian = read_boolean();
}
// No such type in java
public final double read_longdouble()
{
throw wrapper.longDoubleNotImplemented(CompletionStatus.COMPLETED_MAYBE);
}
public final boolean read_boolean()
{
return (read_octet() != 0);
}
public final char read_char()
{
alignAndCheck(1, 1);
return getConvertedChars(1, getCharConverter())[0];
}
public char read_wchar()
{
// Don't allow transmission of wchar/wstring data with foreign ORBs since it's against the spec.
if (ORBUtility.isForeignORB(orb))
{
throw wrapper.wcharDataInGiop10(CompletionStatus.COMPLETED_MAYBE);
}
// If we're talking to one of our legacy ORBs, do what they did:
int b1, b2;
alignAndCheck(2, 2);
if (littleEndian)
{
b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
bbwi.position(bbwi.position() + 1);
b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
bbwi.position(bbwi.position() + 1);
}
else
{
b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
bbwi.position(bbwi.position() + 1);
b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
bbwi.position(bbwi.position() + 1);
}
return (char) ((b1 << 8) + (b2 << 0));
}
public final byte read_octet()
{
alignAndCheck(1, 1);
byte b = bbwi.byteBuffer.get(bbwi.position());
bbwi.position(bbwi.position() + 1);
return b;
}
public final short read_short()
{
int b1, b2;
alignAndCheck(2, 2);
if (littleEndian)
{
b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
bbwi.position(bbwi.position() + 1);
b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
bbwi.position(bbwi.position() + 1);
}
else
{
b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
bbwi.position(bbwi.position() + 1);
b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
bbwi.position(bbwi.position() + 1);
}
return (short) (b1 | b2);
}
public final short read_ushort()
{
return read_short();
}
public final int read_long()
{
int b1, b2, b3, b4;
alignAndCheck(4, 4);
int bufPos = bbwi.position();
if (littleEndian)
{
b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
}
else
{
b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
}
bbwi.position(bufPos);
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
}
public final int read_ulong()
{
return read_long();
}
public final long read_longlong()
{
long i1, i2;
alignAndCheck(8, 8);
if (littleEndian)
{
i2 = read_long() & 0xFFFFFFFFL;
i1 = (long) read_long() << 32;
}
else
{
i1 = (long) read_long() << 32;
i2 = read_long() & 0xFFFFFFFFL;
}
return (i1 | i2);
}
public final long read_ulonglong()
{
return read_longlong();
}
public final float read_float()
{
return Float.intBitsToFloat(read_long());
}
public final double read_double()
{
return Double.longBitsToDouble(read_longlong());
}
protected final void checkForNegativeLength(int length)
{
if (length < 0)
throw wrapper.negativeStringLength(CompletionStatus.COMPLETED_MAYBE, new Integer(length));
}
protected final String readStringOrIndirection(boolean allowIndirection)
{
int len = read_long();
// Check for indirection
if (allowIndirection)
{
if (len == 0xffffffff)
return null;
else
stringIndirection = get_offset() - 4;
}
checkForNegativeLength(len);
if (orb != null && ORBUtility.isLegacyORB(orb))
return legacyReadString(len);
else
return internalReadString(len);
}
private final String internalReadString(int len)
{
// Workaround for ORBs which send string lengths of zero to mean empty string.
//
// IMPORTANT: Do not replace 'new String("")' with "", it may result in a Serialization bug (See
// serialization.zerolengthstring) and bug id: 4728756 for details
if (len == 0)
return new String("");
char[] result = getConvertedChars(len - 1, getCharConverter());
// Skip over the 1 byte null
read_octet();
return new String(result, 0, getCharConverter().getNumChars());
}
private final String legacyReadString(int len)
{
// Workaround for ORBs which send string lengths of zero to mean empty string.
//
// IMPORTANT: Do not replace 'new String("")' with "", it may result in a Serialization bug (See
// serialization.zerolengthstring) and bug id: 4728756 for details
if (len == 0)
return new String("");
len--;
char[] c = new char[len];
int n = 0;
while (n < len)
{
int avail;
int bytes;
int wanted;
avail = bbwi.buflen - bbwi.position();
if (avail <= 0)
{
grow(1, 1);
avail = bbwi.buflen - bbwi.position();
}
wanted = len - n;
bytes = (wanted < avail) ? wanted : avail;
// Microbenchmarks are showing a loop of ByteBuffer.get(int) being faster than ByteBuffer.get(byte[], int,
// int).
for (int i = 0; i < bytes; i++)
{
c[n + i] = (char) (bbwi.byteBuffer.get(bbwi.position() + i) & 0xFF);
}
bbwi.position(bbwi.position() + bytes);
n += bytes;
}
// Skip past terminating null byte
if (bbwi.position() + 1 > bbwi.buflen)
alignAndCheck(1, 1);
bbwi.position(bbwi.position() + 1);
return new String(c);
}
public final String read_string()
{
return readStringOrIndirection(false);
}
public String read_wstring()
{
// Don't allow transmission of wchar/wstring data with foreign ORBs since it's against the spec.
if (ORBUtility.isForeignORB(orb))
{
throw wrapper.wcharDataInGiop10(CompletionStatus.COMPLETED_MAYBE);
}
int len = read_long();
// Workaround for ORBs which send string lengths of zero to mean empty string.
//
// IMPORTANT: Do not replace 'new String("")' with "", it may result in a Serialization bug (See
// serialization.zerolengthstring) and bug id: 4728756 for details
if (len == 0)
return new String("");
checkForNegativeLength(len);
len--;
char[] c = new char[len];
for (int i = 0; i < len; i++)
c[i] = read_wchar();
// skip the two null terminator bytes
read_wchar();
// bbwi.position(bbwi.position() + 2);
return new String(c);
}
public final void read_octet_array(byte[] b, int offset, int length)
{
if (b == null)
throw wrapper.nullParam();
// Must call alignAndCheck at least once to ensure we aren't at the end of a chunk. Of course, we should only
// call it if we actually need to read something, otherwise we might end up with an exception at the end of the
// stream.
if (length == 0)
return;
alignAndCheck(1, 1);
int n = offset;
while (n < length + offset)
{
int avail;
int bytes;
int wanted;
avail = bbwi.buflen - bbwi.position();
if (avail <= 0)
{
grow(1, 1);
avail = bbwi.buflen - bbwi.position();
}
wanted = (length + offset) - n;
bytes = (wanted < avail) ? wanted : avail;
// Microbenchmarks are showing a loop of ByteBuffer.get(int) being faster than ByteBuffer.get(byte[], int,
// int).
for (int i = 0; i < bytes; i++)
{
b[n + i] = bbwi.byteBuffer.get(bbwi.position() + i);
}
bbwi.position(bbwi.position() + bytes);
n += bytes;
}
}
public Principal read_Principal()
{
int len = read_long();
byte[] pvalue = new byte[len];
read_octet_array(pvalue, 0, len);
Principal p = new PrincipalImpl();
p.name(pvalue);
return p;
}
public TypeCode read_TypeCode()
{
TypeCodeImpl tc = new TypeCodeImpl(orb);
tc.read_value(parent);
return tc;
}
public Any read_any()
{
Any any = orb.create_any();
TypeCodeImpl tc = new TypeCodeImpl(orb);
// read off the typecode
// REVISIT We could avoid this try-catch if we could peek the typecode kind off this stream and see if it is a
// tk_value. Looking at the code we know that for tk_value the Any.read_value() below ignores the tc argument
// anyway (except for the kind field). But still we would need to make sure that the whole typecode, including
// encapsulations, is read off.
try
{
tc.read_value(parent);
}
catch (MARSHAL ex)
{
if (tc.kind().value() != TCKind._tk_value)
throw ex;
// We can be sure that the whole typecode encapsulation has been read off.
dprintThrowable(ex);
}
// read off the value of the any
any.read_value(parent, tc);
return any;
}
public org.omg.CORBA.Object read_Object()
{
return read_Object(null);
}
// ------------ RMI related methods --------------------------
// IDL to Java ptc-00-01-08 1.21.4.1
//
// The clz argument to read_Object can be either a stub Class or the
// "Class object for the RMI/IDL interface type that is statically expected." This functions as follows:
// 1. If clz==null, just use the repository ID from the stub
// 2. If clz is a stub class, just use it as a static factory. clz is a stub class if StubAdapter.isStubClass(clz).
// In addition, clz is a IDL stub class if IDLEntity.class.isAssignableFrom( clz ).
// 3. If clz is an interface, use it to create the appropriate stub factory.
public org.omg.CORBA.Object read_Object(Class<?> clz)
{
// In any case, we must first read the IOR.
IOR ior = IORFactories.makeIOR(parent);
if (ior.isNil())
return null;
PresentationManager.StubFactoryFactory sff = ORB.getStubFactoryFactory();
String codeBase = ior.getProfile().getCodebase();
PresentationManager.StubFactory stubFactory = null;
if (clz == null)
{
RepositoryId rid = RepositoryId.cache.getId(ior.getTypeId());
String className = rid.getClassName();
boolean isIDLInterface = rid.isIDLType();
if (className == null || className.equals(""))
stubFactory = null;
else
try
{
stubFactory = sff.createStubFactory(className, isIDLInterface, codeBase, null, (ClassLoader) null);
}
catch (Exception exc)
{
// Could not create stubFactory, so use null.
// XXX stubFactory handling is still too complex: Can we resolve the stubFactory question once in a
// single place?
stubFactory = null;
}
}
else if (StubAdapter.isStubClass(clz))
{
stubFactory = PresentationDefaults.makeStaticStubFactory(clz);
}
else
{
// clz is an interface class
boolean isIDL = IDLEntity.class.isAssignableFrom(clz);
stubFactory = sff.createStubFactory(clz.getName(), isIDL, codeBase, clz, clz.getClassLoader());
}
return internalIORToObject(ior, stubFactory, orb);
}
/*
* This is used as a general utility (e.g., the PortableInterceptor implementation uses it. If stubFactory is null,
* the ior's IIOPProfile must support getServant.
*/
public static org.omg.CORBA.Object internalIORToObject(IOR ior, PresentationManager.StubFactory stubFactory, ORB orb)
{
ORBUtilSystemException wrapper = ORBUtilSystemException.get(orb, CORBALogDomains.RPC_ENCODING);
Object servant = ior.getProfile().getServant();
if (servant != null)
{
if (servant instanceof Tie)
{
String codebase = ior.getProfile().getCodebase();
org.omg.CORBA.Object objref = (org.omg.CORBA.Object) Utility.loadStub((Tie) servant, stubFactory,
codebase, false);
// If we managed to load a stub, return it, otherwise we must fail...
if (objref != null)
{
return objref;
}
else
{
throw wrapper.readObjectException();
}
}
else if (servant instanceof org.omg.CORBA.Object)
{
if (!(servant instanceof org.omg.CORBA.portable.InvokeHandler))
{
return (org.omg.CORBA.Object) servant;
}
}
else
throw wrapper.badServantReadObject();
}
CorbaClientDelegate del = ORBUtility.makeClientDelegate(ior);
org.omg.CORBA.Object objref = null;
try
{
objref = stubFactory.makeStub();
}
catch (Throwable e)
{
wrapper.stubCreateError(e);
if (e instanceof ThreadDeath)
{
throw (ThreadDeath) e;
}
// Return the "default" stub...
objref = new CORBAObjectImpl();
}
StubAdapter.setDelegate(objref, del);
return objref;
}
public Object read_abstract_interface()
{
return read_abstract_interface(null);
}
public Object read_abstract_interface(Class<?> clz)
{
boolean object = read_boolean();
if (object)
{
return read_Object(clz);
}
else
{
return read_value();
}
}
public Serializable read_value()
{
return read_value((Class<?>) null);
}
private Serializable handleIndirection()
{
int indirection = read_long() + get_offset() - 4;
if (valueCache != null && valueCache.containsVal(indirection))
{
java.io.Serializable cachedValue = (java.io.Serializable) valueCache.getKey(indirection);
return cachedValue;
}
else
{
// In RMI-IIOP the ValueHandler will recognize this exception and use the provided indirection value to
// lookup a possible indirection to an object currently on the deserialization stack.
throw new IndirectionException(indirection);
}
}
private String readRepositoryIds(int valueTag, Class<?> expectedType, String expectedTypeRepId)
{
return readRepositoryIds(valueTag, expectedType, expectedTypeRepId, null);
}
/**
* Examines the valuetag to see how many (if any) repository IDs are present on the wire. If no repository ID
* information is on the wire but the expectedType or expectedTypeRepId is known, it will return one of those
* (favoring the expectedType's repId). Failing that, it uses the supplied BoxedValueHelper to obtain the repository
* ID, as a last resort.
*/
private String readRepositoryIds(int valueTag, Class<?> expectedType, String expectedTypeRepId,
BoxedValueHelper factory)
{
switch (repIdUtil.getTypeInfo(valueTag))
{
case RepositoryIdUtility.NO_TYPE_INFO :
// Throw an exception if we have no repository ID info and no expectedType to work with. Otherwise, how
// would we know what to unmarshal?
if (expectedType == null)
{
if (expectedTypeRepId != null)
{
return expectedTypeRepId;
}
else if (factory != null)
{
return factory.get_id();
}
else
{
throw wrapper.expectedTypeNullAndNoRepId(CompletionStatus.COMPLETED_MAYBE);
}
}
return repIdStrs.createForAnyType(expectedType);
case RepositoryIdUtility.SINGLE_REP_TYPE_INFO :
return read_repositoryId();
case RepositoryIdUtility.PARTIAL_LIST_TYPE_INFO :
return read_repositoryIds();
default :
throw wrapper.badValueTag(CompletionStatus.COMPLETED_MAYBE, Integer.toHexString(valueTag));
}
}
public Serializable read_value(Class<?> expectedType)
{
// Read value tag
int vType = readValueTag();
// Is value null?
if (vType == 0)
return null;
// Is this an indirection to a previously read valuetype?
if (vType == 0xffffffff)
return handleIndirection();
// Save where this valuetype started so we can put it in the indirection valueCache later
int indirection = get_offset() - 4;
// Need to save this special marker variable to restore its value during recursion
boolean saveIsChunked = isChunked;
isChunked = repIdUtil.isChunkedEncoding(vType);
Object value = null;
String codebase_URL = null;
if (repIdUtil.isCodeBasePresent(vType))
{
codebase_URL = read_codebase_URL();
}
// Read repository id(s)
String repositoryIDString = readRepositoryIds(vType, expectedType, null);
// If isChunked was determined to be true based on the valuetag, this will read a chunk length
start_block();
// Remember that end_flag keeps track of all nested valuetypes and is used for older ORBs
end_flag--;
if (isChunked)
chunkedValueNestingLevel--;
if (repositoryIDString.equals(repIdStrs.getWStringValueRepId()))
{
value = read_wstring();
}
else if (repositoryIDString.equals(repIdStrs.getClassDescValueRepId()))
{
// read in the class whether with the old ClassDesc or the new one
value = readClass();
}
else
{
Class<?> valueClass = expectedType;
// By this point, either the expectedType or repositoryIDString is guaranteed to be non-null.
if (expectedType == null || !repositoryIDString.equals(repIdStrs.createForAnyType(expectedType)))
{
valueClass = getClassFromString(repositoryIDString, codebase_URL, expectedType);
}
if (valueClass == null)
{
// No point attempting to use value handler below, since the class information is not available.
throw wrapper.couldNotFindClass(CompletionStatus.COMPLETED_MAYBE, new ClassNotFoundException());
}
if (valueClass != null && org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(valueClass))
{
value = readIDLValue(indirection, repositoryIDString, valueClass, codebase_URL);
}
else
{
// Must be some form of RMI-IIOP valuetype
try
{
if (valueHandler == null)
valueHandler = ORBUtility.createValueHandler(orb);
value = valueHandler.readValue(parent, indirection, valueClass, repositoryIDString, getCodeBase());
}
catch (SystemException sysEx)
{
// Just rethrow any CORBA system exceptions that come out of the ValueHandler
throw sysEx;
}
catch (Exception ex)
{
throw wrapper.valuehandlerReadException(CompletionStatus.COMPLETED_MAYBE, ex);
}
catch (Error e)
{
throw wrapper.valuehandlerReadError(CompletionStatus.COMPLETED_MAYBE, e);
}
}
}
// Skip any remaining chunks until we get to an end tag or a valuetag. If we see a valuetag, that means there
// was another valuetype in the sender's version of this class that we need to skip over.
handleEndOfValue();
// Read and process the end tag if we're chunking. Assumes that we're at the position of the end tag
// (handleEndOfValue should assure this)
readEndTag();
// Cache the valuetype that we read
if (valueCache == null)
valueCache = new CacheTable(orb, false);
valueCache.put(value, indirection);
// Allow for possible continuation chunk. If we're a nested valuetype inside of a chunked valuetype, and that
// enclosing valuetype has more data to write, it will need to have this new chunk begin after we wrote our end
// tag.
isChunked = saveIsChunked;
start_block();
return (java.io.Serializable) value;
}
public Serializable read_value(BoxedValueHelper factory)
{
// Read value tag
int vType = readValueTag();
if (vType == 0)
return null; // value is null
else if (vType == 0xffffffff)
{ // Indirection tag
int indirection = read_long() + get_offset() - 4;
if (valueCache != null && valueCache.containsVal(indirection))
{
java.io.Serializable cachedValue = (java.io.Serializable) valueCache.getKey(indirection);
return cachedValue;
}
else
{
throw new IndirectionException(indirection);
}
}
else
{
int indirection = get_offset() - 4;
// end_block();
boolean saveIsChunked = isChunked;
isChunked = repIdUtil.isChunkedEncoding(vType);
Object value = null;
String codebase_URL = null;
if (repIdUtil.isCodeBasePresent(vType))
{
codebase_URL = read_codebase_URL();
}
// Read repository id
String repositoryIDString = readRepositoryIds(vType, null, null, factory);
// Compare rep. ids to see if we should use passed helper
if (!repositoryIDString.equals(factory.get_id()))
factory = Utility.getHelper(null, codebase_URL, repositoryIDString);
start_block();
end_flag--;
if (isChunked)
chunkedValueNestingLevel--;
if (factory instanceof ValueHelper)
{
value = readIDLValueWithHelper((ValueHelper) factory, indirection);
}
else
{
valueIndirection = indirection; // for callback
value = factory.read_value(parent);
}
handleEndOfValue();
readEndTag();
// Put into valueCache
if (valueCache == null)
valueCache = new CacheTable(orb, false);
valueCache.put(value, indirection);
// allow for possible continuation chunk
isChunked = saveIsChunked;
start_block();
return (java.io.Serializable) value;
}
}
private boolean isCustomType(ValueHelper helper)
{
try
{
TypeCode tc = helper.get_type();
int kind = tc.kind().value();
if (kind == TCKind._tk_value)
{
return (tc.type_modifier() == org.omg.CORBA.VM_CUSTOM.value);
}
}
catch (BadKind ex)
{
throw wrapper.badKind(ex);
}
return false;
}
// This method is actually called indirectly by read_value(String repositoryId). Therefore, it is not a truly
// independent read call that handles header information itself.
public java.io.Serializable read_value(java.io.Serializable value)
{
// Put into valueCache using valueIndirection
if (valueCache == null)
valueCache = new CacheTable(orb, false);
valueCache.put(value, valueIndirection);
if (value instanceof StreamableValue)
((StreamableValue) value)._read(parent);
else if (value instanceof CustomValue)
((CustomValue) value).unmarshal(parent);
return value;
}
public java.io.Serializable read_value(String repositoryId)
{
// if (inBlock)
// end_block();
// Read value tag
int vType = readValueTag();
if (vType == 0)
return null; // value is null
else if (vType == 0xffffffff)
{ // Indirection tag
int indirection = read_long() + get_offset() - 4;
if (valueCache != null && valueCache.containsVal(indirection))
{
java.io.Serializable cachedValue = (java.io.Serializable) valueCache.getKey(indirection);
return cachedValue;
}
else
{
throw new IndirectionException(indirection);
}
}
else
{
int indirection = get_offset() - 4;
// end_block();
boolean saveIsChunked = isChunked;
isChunked = repIdUtil.isChunkedEncoding(vType);
Object value = null;
String codebase_URL = null;
if (repIdUtil.isCodeBasePresent(vType))
{
codebase_URL = read_codebase_URL();
}
// Read repository id
String repositoryIDString = readRepositoryIds(vType, null, repositoryId);
ValueFactory factory = Utility.getFactory(null, codebase_URL, orb, repositoryIDString);
start_block();
end_flag--;
if (isChunked)
chunkedValueNestingLevel--;
valueIndirection = indirection; // for callback
value = factory.read_value(parent);
handleEndOfValue();
readEndTag();
// Put into valueCache
if (valueCache == null)
valueCache = new CacheTable(orb, false);
valueCache.put(value, indirection);
// allow for possible continuation chunk
isChunked = saveIsChunked;
start_block();
return (java.io.Serializable) value;
}
}
private Class<?> readClass()
{
String codebases = null, classRepId = null;
if (orb == null || ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion())
|| ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0)
{
codebases = (String) read_value(String.class);
classRepId = (String) read_value(String.class);
}
else
{
// Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID and codebase strings in the wrong order.
classRepId = (String) read_value(String.class);
codebases = (String) read_value(String.class);
}
if (debug)
{
dprint("readClass codebases: " + codebases + " rep Id: " + classRepId);
}
Class<?> cl = null;
RepositoryIdInterface repositoryID = repIdStrs.getFromString(classRepId);
try
{
cl = repositoryID.getClassFromType(codebases);
}
catch (ClassNotFoundException cnfe)
{
throw wrapper.cnfeReadClass(CompletionStatus.COMPLETED_MAYBE, cnfe, repositoryID.getClassName());
}
catch (MalformedURLException me)
{
throw wrapper.malformedUrl(CompletionStatus.COMPLETED_MAYBE, me, repositoryID.getClassName(), codebases);
}
return cl;
}
private Object readIDLValueWithHelper(ValueHelper helper, int indirection)
{
// look for two-argument static read method
Method readMethod;
try
{
Class<?> argTypes[] = {org.omg.CORBA.portable.InputStream.class, helper.get_class()};
readMethod = helper.getClass().getDeclaredMethod(kReadMethod, argTypes);
}
catch (NoSuchMethodException nsme)
{ // must be boxed value helper
Object result = helper.read_value(parent);
return result;
}
// found two-argument read method, so must be non-boxed value... create a blank instance
Object val = null;
try
{
val = helper.get_class().newInstance();
}
catch (InstantiationException ie)
{
throw wrapper.couldNotInstantiateHelper(ie, helper.get_class());
}
catch (IllegalAccessException iae)
{
// Value's constructor is protected or private
//
// So, use the helper to read the value.
//
// NOTE : This means that in this particular case a recursive ref would fail.
return helper.read_value(parent);
}
// add blank instance to cache table
if (valueCache == null)
valueCache = new CacheTable(orb, false);
valueCache.put(val, indirection);
// if custom type, call unmarshal method
if (val instanceof CustomMarshal && isCustomType(helper))
{
((CustomMarshal) val).unmarshal(parent);
return val;
}
// call two-argument read method using reflection
try
{
Object args[] = {parent, val};
readMethod.invoke(helper, args);
return val;
}
catch (IllegalAccessException iae2)
{
throw wrapper.couldNotInvokeHelperReadMethod(iae2, helper.get_class());
}
catch (InvocationTargetException ite)
{
throw wrapper.couldNotInvokeHelperReadMethod(ite, helper.get_class());
}
}
private Object readBoxedIDLEntity(Class<?> clazz, String codebase)
{
Class<?> cls = null;
try
{
ClassLoader clazzLoader = (clazz == null ? null : clazz.getClassLoader());
cls = Utility.loadClassForClass(clazz.getName() + "Helper", codebase, clazzLoader, clazz, clazzLoader);
final Class<?> helperClass = cls;
final Class<?> argTypes[] = {org.omg.CORBA.portable.InputStream.class};
// getDeclaredMethod requires RuntimePermission accessDeclaredMembers if a different class loader is used
// (even though the javadoc says otherwise)
Method readMethod = null;
try
{
readMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>()
{
public Method run() throws NoSuchMethodException
{
return helperClass.getDeclaredMethod(kReadMethod, argTypes);
}
});
}
catch (PrivilegedActionException pae)
{
// this gets caught below
throw (NoSuchMethodException) pae.getException();
}
Object args[] = {parent};
return readMethod.invoke(null, args);
}
catch (ClassNotFoundException cnfe)
{
throw wrapper.couldNotInvokeHelperReadMethod(cnfe, cls);
}
catch (NoSuchMethodException nsme)
{
throw wrapper.couldNotInvokeHelperReadMethod(nsme, cls);
}
catch (IllegalAccessException iae)
{
throw wrapper.couldNotInvokeHelperReadMethod(iae, cls);
}
catch (InvocationTargetException ite)
{
throw wrapper.couldNotInvokeHelperReadMethod(ite, cls);
}
}
private Object readIDLValue(int indirection, String repId, Class<?> clazz, String codebase)
{
ValueFactory factory;
// Always try to find a ValueFactory first, as required by the spec.
// There are some complications here in the IDL 3.0 mapping (see 1.13.8), but basically we must always be able
// to override the DefaultFactory or Helper mappings that are also used. This appears to be the case even in the
// boxed value cases. The original code only did the lookup in the case of class implementing either
// StreamableValue or CustomValue, but abstract valuetypes only implement ValueBase, and really require the use
// of the repId to find a factory (including the DefaultFactory).
try
{
// use new-style OBV support (factory object)
factory = Utility.getFactory(clazz, codebase, orb, repId);
}
catch (MARSHAL marshal)
{
// XXX log marshal at one of the INFO levels
// Could not get a factory, so try alternatives
if (!StreamableValue.class.isAssignableFrom(clazz) && !CustomValue.class.isAssignableFrom(clazz)
&& ValueBase.class.isAssignableFrom(clazz))
{
// use old-style OBV support (helper object)
BoxedValueHelper helper = Utility.getHelper(clazz, codebase, repId);
if (helper instanceof ValueHelper)
return readIDLValueWithHelper((ValueHelper) helper, indirection);
else
return helper.read_value(parent);
}
else
{
// must be a boxed IDLEntity, so make a reflective call to the
// helper's static read method...
return readBoxedIDLEntity(clazz, codebase);
}
}
// If there was no error in getting the factory, use it.
valueIndirection = indirection; // for callback
return factory.read_value(parent);
}
/**
* End tags are only written for chunked valuetypes.
*
* Before Merlin, our ORBs wrote end tags which took into account all enclosing valuetypes. This was changed by an
* interop resolution (see details around chunkedValueNestingLevel) to only include enclosing chunked types.
*
* ORB versioning and end tag compaction are handled here.
*/
private void readEndTag()
{
if (isChunked)
{
// Read the end tag
int anEndTag = read_long();
// End tags should always be negative, and the outermost enclosing chunked valuetype should have a -1 end
// tag.
//
// handleEndOfValue should have assured that we were at the end tag position!
if (anEndTag >= 0)
{
throw wrapper.positiveEndTag(CompletionStatus.COMPLETED_MAYBE, new Integer(anEndTag), new Integer(
get_offset() - 4));
}
// If the ORB is null, or if we're sure we're talking to a foreign ORB, Merlin, or something more recent, we
// use the updated end tag computation, and are more strenuous about the values.
if (orb == null || ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion())
|| ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0)
{
// If the end tag we read was less than what we were expecting, then the sender must think it's sent
// more enclosing chunked valuetypes than we have. Throw an exception.
if (anEndTag < chunkedValueNestingLevel)
throw wrapper.unexpectedEnclosingValuetype(CompletionStatus.COMPLETED_MAYBE, new Integer(anEndTag),
new Integer(chunkedValueNestingLevel));
// If the end tag is bigger than what we expected, but still negative, then the sender has done some end
// tag compaction. We back up the stream 4 bytes so that the next time readEndTag is called, it will get
// down here again. Even with fragmentation, we'll always be able to do this.
if (anEndTag != chunkedValueNestingLevel)
{
bbwi.position(bbwi.position() - 4);
}
}
else
{
// When talking to Kestrel or Ladybird, we use our old end tag rules and are less strict. If the end tag
// isn't what we expected, we back up, assuming compaction.
if (anEndTag != end_flag)
{
bbwi.position(bbwi.position() - 4);
}
}
// This only keeps track of the enclosing chunked valuetypes
chunkedValueNestingLevel++;
}
// This keeps track of all enclosing valuetypes
end_flag++;
}
protected int get_offset()
{
return bbwi.position();
}
private void start_block()
{
// if (outerValueDone)
if (!isChunked)
return;
// if called from alignAndCheck, need to reset blockLength to avoid an infinite recursion loop on read_long()
// call
blockLength = maxBlockLength;
blockLength = read_long();
// Must remember where we began the chunk to calculate how far along we are. See notes above about
// chunkBeginPos.
if (blockLength > 0 && blockLength < maxBlockLength)
{
blockLength += get_offset(); // _REVISIT_ unsafe, should use a Java long
// inBlock = true;
}
else
{
// System.out.println("start_block snooped a " + Integer.toHexString(blockLength));
// not a chunk length field
blockLength = maxBlockLength;
bbwi.position(bbwi.position() - 4);
}
}
// Makes sure that if we were reading a chunked value, we end up at the right place in the stream, no matter how
// little the unmarshalling code read.
//
// After calling this method, if we are chunking, we should be in position to read the end tag.
private void handleEndOfValue()
{
// If we're not chunking, we don't have to worry about skipping remaining chunks or finding end tags
if (!isChunked)
return;
// Skip any remaining chunks
while (blockLength != maxBlockLength)
{
end_block();
start_block();
}
// Now look for the end tag
// This is a little wasteful since we're reading this long up to 3 times in the worst cases (once in
// start_block, once here, and once in readEndTag
//
// Peek next long
int nextLong = read_long();
bbwi.position(bbwi.position() - 4);
// We did find an end tag, so we're done. readEndTag should take care of making sure it's the correct end tag,
// etc. Remember that since end tags, chunk lengths, and valuetags have non overlapping ranges, we can tell by
// the value what the longs are.
if (nextLong < 0)
return;
if (nextLong == 0 || nextLong >= maxBlockLength)
{
// A custom marshaled valuetype left extra data on the wire, and that data had another nested value inside
// of it. We've just read the value tag or null of that nested value.
//
// In an attempt to get by it, we'll try to call read_value() to get the nested value off of the wire.
// Afterwards, we must call handleEndOfValue recursively to read any further chunks that the containing
// valuetype might still have after the nested value.
read_value();
handleEndOfValue();
}
else
{
// This probably means that the code to skip chunks has an error, and ended up setting blockLength to
// something other than maxBlockLength even though we weren't starting a new chunk.
throw wrapper.couldNotSkipBytes(CompletionStatus.COMPLETED_MAYBE, new Integer(nextLong), new Integer(
get_offset()));
}
}
private void end_block()
{
// if in a chunk, check for underflow or overflow
if (blockLength != maxBlockLength)
{
if (blockLength == get_offset())
{
// Chunk ended correctly
blockLength = maxBlockLength;
}
else
{
// Skip over anything left by bad unmarshaling code (ex: a buggy custom unmarshaler). See
// handleEndOfValue.
if (blockLength > get_offset())
{
skipToOffset(blockLength);
}
else
{
throw wrapper.badChunkLength(new Integer(blockLength), new Integer(get_offset()));
}
}
}
}
private int readValueTag()
{
// outerValueDone = false;
return read_long();
}
public org.omg.CORBA.ORB orb()
{
return orb;
}
// ------------ End RMI related methods --------------------------
public final void read_boolean_array(boolean[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_boolean();
}
}
public final void read_char_array(char[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_char();
}
}
public final void read_wchar_array(char[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_wchar();
}
}
public final void read_short_array(short[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_short();
}
}
public final void read_ushort_array(short[] value, int offset, int length)
{
read_short_array(value, offset, length);
}
public final void read_long_array(int[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_long();
}
}
public final void read_ulong_array(int[] value, int offset, int length)
{
read_long_array(value, offset, length);
}
public final void read_longlong_array(long[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_longlong();
}
}
public final void read_ulonglong_array(long[] value, int offset, int length)
{
read_longlong_array(value, offset, length);
}
public final void read_float_array(float[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_float();
}
}
public final void read_double_array(double[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_double();
}
}
public final void read_any_array(org.omg.CORBA.Any[] value, int offset, int length)
{
for (int i = 0; i < length; i++)
{
value[i + offset] = read_any();
}
}
// -------------------------------------------------------------------- //
// CDRInputStream state management.
// -------------------------------------------------------------------- //
/**
* Are we at the end of the input stream?
*/
// public final boolean isAtEnd() {
// return bbwi.position() == bbwi.buflen;
// }
// public int available() throws IOException {
// return bbwi.buflen - bbwi.position();
// }
private String read_repositoryIds()
{
// Read # of repository ids
int numRepIds = read_long();
if (numRepIds == 0xffffffff)
{
int indirection = read_long() + get_offset() - 4;
if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
return (String) repositoryIdCache.getKey(indirection);
else
throw wrapper.unableToLocateRepIdArray(new Integer(indirection));
}
else
{
// read first array element and store it as an indirection to the whole array
int indirection = get_offset();
String repID = read_repositoryId();
if (repositoryIdCache == null)
repositoryIdCache = new CacheTable(orb, false);
repositoryIdCache.put(repID, indirection);
// read and ignore the subsequent array elements, but put them in the indirection table in case there are
// later indirections back to them
for (int i = 1; i < numRepIds; i++)
{
read_repositoryId();
}
return repID;
}
}
private final String read_repositoryId()
{
String result = readStringOrIndirection(true);
if (result == null)
{ // Indirection
int indirection = read_long() + get_offset() - 4;
if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
return (String) repositoryIdCache.getKey(indirection);
else
throw wrapper.badRepIdIndirection(CompletionStatus.COMPLETED_MAYBE, new Integer(bbwi.position()));
}
else
{
if (repositoryIdCache == null)
repositoryIdCache = new CacheTable(orb, false);
repositoryIdCache.put(result, stringIndirection);
}
return result;
}
private final String read_codebase_URL()
{
String result = readStringOrIndirection(true);
if (result == null)
{ // Indirection
int indirection = read_long() + get_offset() - 4;
if (codebaseCache != null && codebaseCache.containsVal(indirection))
return (String) codebaseCache.getKey(indirection);
else
throw wrapper.badCodebaseIndirection(CompletionStatus.COMPLETED_MAYBE, new Integer(bbwi.position()));
}
else
{
if (codebaseCache == null)
codebaseCache = new CacheTable(orb, false);
codebaseCache.put(result, stringIndirection);
}
return result;
}
/* DataInputStream methods */
public Object read_Abstract()
{
return read_abstract_interface();
}
public java.io.Serializable read_Value()
{
return read_value();
}
public void read_any_array(org.omg.CORBA.AnySeqHolder seq, int offset, int length)
{
read_any_array(seq.value, offset, length);
}
public void read_boolean_array(org.omg.CORBA.BooleanSeqHolder seq, int offset, int length)
{
read_boolean_array(seq.value, offset, length);
}
public void read_char_array(org.omg.CORBA.CharSeqHolder seq, int offset, int length)
{
read_char_array(seq.value, offset, length);
}
public void read_wchar_array(org.omg.CORBA.WCharSeqHolder seq, int offset, int length)
{
read_wchar_array(seq.value, offset, length);
}
public void read_octet_array(org.omg.CORBA.OctetSeqHolder seq, int offset, int length)
{
read_octet_array(seq.value, offset, length);
}
public void read_short_array(org.omg.CORBA.ShortSeqHolder seq, int offset, int length)
{
read_short_array(seq.value, offset, length);
}
public void read_ushort_array(org.omg.CORBA.UShortSeqHolder seq, int offset, int length)
{
read_ushort_array(seq.value, offset, length);
}
public void read_long_array(org.omg.CORBA.LongSeqHolder seq, int offset, int length)
{
read_long_array(seq.value, offset, length);
}
public void read_ulong_array(org.omg.CORBA.ULongSeqHolder seq, int offset, int length)
{
read_ulong_array(seq.value, offset, length);
}
public void read_ulonglong_array(org.omg.CORBA.ULongLongSeqHolder seq, int offset, int length)
{
read_ulonglong_array(seq.value, offset, length);
}
public void read_longlong_array(org.omg.CORBA.LongLongSeqHolder seq, int offset, int length)
{
read_longlong_array(seq.value, offset, length);
}
public void read_float_array(org.omg.CORBA.FloatSeqHolder seq, int offset, int length)
{
read_float_array(seq.value, offset, length);
}
public void read_double_array(org.omg.CORBA.DoubleSeqHolder seq, int offset, int length)
{
read_double_array(seq.value, offset, length);
}
public java.math.BigDecimal read_fixed(short digits, short scale)
{
// digits isn't really needed here
StringBuffer buffer = read_fixed_buffer();
if (digits != buffer.length())
throw wrapper.badFixed(new Integer(digits), new Integer(buffer.length()));
buffer.insert(digits - scale, '.');
return new BigDecimal(buffer.toString());
}
// This method is unable to yield the correct scale.
public java.math.BigDecimal read_fixed()
{
return new BigDecimal(read_fixed_buffer().toString());
}
// Each octet contains (up to) two decimal digits. If the fixed type has an odd number of decimal digits, then the
// representation begins with the first (most significant) digit. Otherwise, this first half-octet is all zero, and
// the first digit is in the second half-octet. The sign configuration, in the last half-octet of the
// representation, is 0xD for negative numbers and 0xC for positive and zero values.
private StringBuffer read_fixed_buffer()
{
StringBuffer buffer = new StringBuffer(64);
byte doubleDigit;
int firstDigit;
int secondDigit;
boolean wroteFirstDigit = false;
boolean more = true;
while (more)
{
doubleDigit = this.read_octet();
firstDigit = ((doubleDigit & 0xf0) >> 4);
secondDigit = (doubleDigit & 0x0f);
if (wroteFirstDigit || firstDigit != 0)
{
buffer.append(Character.forDigit(firstDigit, 10));
wroteFirstDigit = true;
}
if (secondDigit == 12)
{
// positive number or zero
if (!wroteFirstDigit)
{
// zero
return new StringBuffer("0.0");
}
else
{
// positive number - done
}
more = false;
}
else if (secondDigit == 13)
{
// negative number
buffer.insert(0, '-');
more = false;
}
else
{
buffer.append(Character.forDigit(secondDigit, 10));
wroteFirstDigit = true;
}
}
return buffer;
}
private final static String _id = "IDL:omg.org/CORBA/DataInputStream:1.0";
private final static String[] _ids = {_id};
public String[] _truncatable_ids()
{
if (_ids == null)
return null;
return _ids.clone();
}
/* for debugging */
public void printBuffer()
{
CDRInputStream_1_0.printBuffer(this.bbwi);
}
public static void printBuffer(ByteBufferWithInfo bbwi)
{
System.out.println("----- Input Buffer -----");
System.out.println();
System.out.println("Current position: " + bbwi.position());
System.out.println("Total length : " + bbwi.buflen);
System.out.println();
try
{
char[] charBuf = new char[16];
for (int i = 0; i < bbwi.buflen; i += 16)
{
int j = 0;
// For every 16 bytes, there is one line of output. First, the hex output of the 16 bytes with each byte
// separated by a space.
while (j < 16 && j + i < bbwi.buflen)
{
int k = bbwi.byteBuffer.get(i + j);
if (k < 0)
k = 256 + k;
String hex = Integer.toHexString(k);
if (hex.length() == 1)
hex = "0" + hex;
System.out.print(hex + " ");
j++;
}
// Add any extra spaces to align the text column in case we didn't end at 16
while (j < 16)
{
System.out.print(" ");
j++;
}
// Now output the ASCII equivalents. Non-ASCII characters are shown as periods.
int x = 0;
while (x < 16 && x + i < bbwi.buflen)
{
if (ORBUtility.isPrintable((char) bbwi.byteBuffer.get(i + x)))
charBuf[x] = (char) bbwi.byteBuffer.get(i + x);
else
charBuf[x] = '.';
x++;
}
System.out.println(new String(charBuf, 0, x));
}
}
catch (Throwable t)
{
t.printStackTrace();
}
System.out.println("------------------------");
}
public ByteBuffer getByteBuffer()
{
ByteBuffer result = null;
if (bbwi != null)
{
result = bbwi.byteBuffer;
}
return result;
}
public int getBufferLength()
{
return bbwi.buflen;
}
public void setBufferLength(int value)
{
bbwi.buflen = value;
bbwi.byteBuffer.limit(bbwi.buflen);
}
public void setByteBufferWithInfo(ByteBufferWithInfo bbwi)
{
this.bbwi = bbwi;
}
public void setByteBuffer(ByteBuffer byteBuffer)
{
bbwi.byteBuffer = byteBuffer;
}
public int getIndex()
{
return bbwi.position();
}
public void setIndex(int value)
{
bbwi.position(value);
}
public boolean isLittleEndian()
{
return littleEndian;
}
public void orb(org.omg.CORBA.ORB orb)
{
this.orb = (ORB) orb;
}
public BufferManagerRead getBufferManager()
{
return bufferManagerRead;
}
private void skipToOffset(int offset)
{
// Number of bytes to skip
int len = offset - get_offset();
int n = 0;
while (n < len)
{
int avail;
int bytes;
int wanted;
avail = bbwi.buflen - bbwi.position();
if (avail <= 0)
{
grow(1, 1);
avail = bbwi.buflen - bbwi.position();
}
wanted = len - n;
bytes = (wanted < avail) ? wanted : avail;
bbwi.position(bbwi.position() + bytes);
n += bytes;
}
}
// Mark and reset -------------------------------------------------
protected MarkAndResetHandler markAndResetHandler = null;
protected class StreamMemento
{
// These are the fields that may change after marking the stream position, so we need to save them.
private int blockLength_;
private int end_flag_;
private int chunkedValueNestingLevel_;
private int valueIndirection_;
private int stringIndirection_;
private boolean isChunked_;
private javax.rmi.CORBA.ValueHandler valueHandler_;
private ByteBufferWithInfo bbwi_;
private boolean specialNoOptionalDataState_;
public StreamMemento()
{
blockLength_ = blockLength;
end_flag_ = end_flag;
chunkedValueNestingLevel_ = chunkedValueNestingLevel;
valueIndirection_ = valueIndirection;
stringIndirection_ = stringIndirection;
isChunked_ = isChunked;
valueHandler_ = valueHandler;
specialNoOptionalDataState_ = specialNoOptionalDataState;
bbwi_ = new ByteBufferWithInfo(bbwi);
}
}
public Object createStreamMemento()
{
return new StreamMemento();
}
public void restoreInternalState(Object streamMemento)
{
StreamMemento mem = (StreamMemento) streamMemento;
blockLength = mem.blockLength_;
end_flag = mem.end_flag_;
chunkedValueNestingLevel = mem.chunkedValueNestingLevel_;
valueIndirection = mem.valueIndirection_;
stringIndirection = mem.stringIndirection_;
isChunked = mem.isChunked_;
valueHandler = mem.valueHandler_;
specialNoOptionalDataState = mem.specialNoOptionalDataState_;
bbwi = mem.bbwi_;
}
public int getPosition()
{
return get_offset();
}
public void mark(int readlimit)
{
markAndResetHandler.mark(this);
}
public void reset()
{
markAndResetHandler.reset();
}
// ---------------------------------- end Mark and Reset
// Provides a hook so subclasses of CDRInputStream can provide a CodeBase. This ultimately allows us to grab a
// Connection instance in IIOPInputStream, the only subclass where this is actually used.
CodeBase getCodeBase()
{
return parent.getCodeBase();
}
/**
* Attempts to find the class described by the given repository ID string and expected type. The first attempt is to
* find the class locally, falling back on the URL that came with the value. The second attempt is to use a URL from
* the remote CodeBase.
*/
private Class<?> getClassFromString(String repositoryIDString, String codebaseURL, Class<?> expectedType)
{
RepositoryIdInterface repositoryID = repIdStrs.getFromString(repositoryIDString);
try
{
try
{
// First try to load the class locally, then use the provided URL (if it isn't null)
return repositoryID.getClassFromType(expectedType, codebaseURL);
}
catch (ClassNotFoundException cnfeOuter)
{
try
{
if (getCodeBase() == null)
{
return null; // class cannot be loaded remotely.
}
// Get a URL from the remote CodeBase and retry
codebaseURL = getCodeBase().implementation(repositoryIDString);
// Don't bother trying to find it locally again if we got a null URL
if (codebaseURL == null)
return null;
return repositoryID.getClassFromType(expectedType, codebaseURL);
}
catch (ClassNotFoundException cnfeInner)
{
dprintThrowable(cnfeInner);
// Failed to load the class
return null;
}
}
}
catch (MalformedURLException mue)
{
// Always report a bad URL
throw wrapper.malformedUrl(CompletionStatus.COMPLETED_MAYBE, mue, repositoryIDString, codebaseURL);
}
}
// Utility method used to get chars from bytes
char[] getConvertedChars(int numBytes, CodeSetConversion.BTCConverter converter)
{
// REVISIT - Look at CodeSetConversion.BTCConverter to see if it can work with an NIO ByteBuffer. We should
// avoid getting the bytes into an array if possible.
// To be honest, I doubt this saves much real time
if (bbwi.buflen - bbwi.position() >= numBytes)
{
// If the entire string is in this buffer, just convert directly from the bbwi rather than allocating and
// copying.
byte[] tmpBuf;
if (bbwi.byteBuffer.hasArray())
{
tmpBuf = bbwi.byteBuffer.array();
}
else
{
tmpBuf = new byte[bbwi.buflen];
// Microbenchmarks are showing a loop of ByteBuffer.get(int) being faster than ByteBuffer.get(byte[],
// int, int).
for (int i = 0; i < bbwi.buflen; i++)
tmpBuf[i] = bbwi.byteBuffer.get(i);
}
char[] result = converter.getChars(tmpBuf, bbwi.position(), numBytes);
bbwi.position(bbwi.position() + numBytes);
return result;
}
else
{
// Stretches across buffers. Unless we provide an incremental conversion interface, allocate and copy the
// bytes.
byte[] bytes = new byte[numBytes];
read_octet_array(bytes, 0, bytes.length);
return converter.getChars(bytes, 0, numBytes);
}
}
protected CodeSetConversion.BTCConverter getCharConverter()
{
if (charConverter == null)
charConverter = parent.createCharBTCConverter();
return charConverter;
}
protected CodeSetConversion.BTCConverter getWCharConverter()
{
if (wcharConverter == null)
wcharConverter = parent.createWCharBTCConverter();
return wcharConverter;
}
protected void dprintThrowable(Throwable t)
{
if (debug && t != null)
t.printStackTrace();
}
protected void dprint(String msg)
{
if (debug)
{
ORBUtility.dprint(this, msg);
}
}
/**
* Aligns the current position on the given octet boundary if there are enough bytes available to do so. Otherwise,
* it just returns. This is used for some (but not all) GIOP 1.2 message headers.
*/
void alignOnBoundary(int octetBoundary)
{
int needed = computeAlignment(bbwi.position(), octetBoundary);
if (bbwi.position() + needed <= bbwi.buflen)
{
bbwi.position(bbwi.position() + needed);
}
}
public void resetCodeSetConverters()
{
charConverter = null;
wcharConverter = null;
}
public void start_value()
{
// Read value tag
int vType = readValueTag();
if (vType == 0)
{
// Stream needs to go into a state where it throws standard exception until end_value is called. This means
// the sender didn't send any custom data. If the reader here tries to read more, we need to throw an
// exception before reading beyond where we're supposed to
specialNoOptionalDataState = true;
return;
}
if (vType == 0xffffffff)
{
// One should never indirect to a custom wrapper
throw wrapper.customWrapperIndirection(CompletionStatus.COMPLETED_MAYBE);
}
if (repIdUtil.isCodeBasePresent(vType))
{
throw wrapper.customWrapperWithCodebase(CompletionStatus.COMPLETED_MAYBE);
}
if (repIdUtil.getTypeInfo(vType) != RepositoryIdUtility.SINGLE_REP_TYPE_INFO)
{
throw wrapper.customWrapperNotSingleRepid(CompletionStatus.COMPLETED_MAYBE);
}
// REVISIT - Could verify repository ID even though it isn't used elsewhere
read_repositoryId();
// Note: isChunked should be true here. Should have been set to true in the containing value's read_value
// method.
start_block();
end_flag--;
chunkedValueNestingLevel--;
}
public void end_value()
{
if (specialNoOptionalDataState)
{
specialNoOptionalDataState = false;
return;
}
handleEndOfValue();
readEndTag();
// Note that isChunked should still be true here. If the containing valuetype is the highest chunked value, it
// will get set to false at the end of read_value.
// allow for possible continuation chunk
start_block();
}
public void close() throws IOException
{
// tell BufferManagerRead to release any ByteBuffers
getBufferManager().close(bbwi);
// It's possible bbwi.byteBuffer is shared between this InputStream and an OutputStream. Thus, we check if the
// Input/Output streams are using the same ByteBuffer. If they sharing the same ByteBuffer we need to ensure
// only one of those ByteBuffers are released to the ByteBufferPool.
if (bbwi != null && getByteBuffer() != null)
{
int bbHash = System.identityHashCode(bbwi.byteBuffer);
MessageMediator messageMediator = parent.getMessageMediator();
if (messageMediator != null)
{
CDROutputObject outputObj = (CDROutputObject) messageMediator.getOutputObject();
if (outputObj != null)
{
ByteBuffer outputBb = outputObj.getByteBuffer();
int oBbHash = 0;
if (outputBb != null)
{
oBbHash = System.identityHashCode(outputBb);
if (bbHash == oBbHash) // shared?
{
// Set OutputStream's ByteBuffer and bbwi to null so its ByteBuffer cannot be released to the pool
outputObj.setByteBuffer(null);
outputObj.setByteBufferWithInfo(null);
}
}
}
}
// release this stream's ByteBuffer to the pool
ByteBufferPool byteBufferPool = orb.getByteBufferPool();
if (debug)
{
// print address of ByteBuffer being released
int bbAddress = System.identityHashCode(bbwi.byteBuffer);
StringBuffer sb = new StringBuffer(80);
sb.append(".close - releasing ByteBuffer id (");
sb.append(bbAddress).append(") to ByteBufferPool.");
String msg = sb.toString();
dprint(msg);
}
byteBufferPool.releaseByteBuffer(bbwi.byteBuffer);
bbwi.byteBuffer = null;
bbwi = null;
}
}
}