blob: a00d66cb5b5345db3c5855bcd44b6ed2a60a7524 [file] [log] [blame]
/*
* Copyright (c) 1997, 2012, 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 com.sun.corba.se.impl.encoding;
import java.io.IOException;
import java.io.Serializable;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.io.OptionalDataException;
import java.io.IOException;
import java.util.Stack;
import java.net.URL;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.rmi.Remote;
import java.rmi.StubNotFoundException;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.Object;
import org.omg.CORBA.Principal;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.Any;
import org.omg.CORBA.portable.Delegate;
import org.omg.CORBA.portable.ValueBase;
import org.omg.CORBA.portable.IndirectionException;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.CustomMarshal;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.Principal;
import org.omg.CORBA.Any;
import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA.portable.ValueFactory;
import org.omg.CORBA.portable.CustomValue;
import org.omg.CORBA.portable.StreamableValue;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.portable.IDLEntity;
import javax.rmi.PortableRemoteObject;
import javax.rmi.CORBA.Tie;
import javax.rmi.CORBA.Util;
import javax.rmi.CORBA.ValueHandler;
import com.sun.corba.se.pept.protocol.MessageMediator;
import com.sun.corba.se.pept.transport.ByteBufferPool;
import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
import com.sun.corba.se.spi.protocol.CorbaClientDelegate;
import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.orb.ORBVersionFactory;
import com.sun.corba.se.spi.orb.ORBVersion;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.presentation.rmi.PresentationManager;
import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
import com.sun.corba.se.spi.presentation.rmi.PresentationDefaults;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.logging.OMGSystemException;
import com.sun.corba.se.impl.corba.PrincipalImpl;
import com.sun.corba.se.impl.corba.TypeCodeImpl;
import com.sun.corba.se.impl.corba.CORBAObjectImpl;
import com.sun.corba.se.impl.encoding.CDROutputObject;
import com.sun.corba.se.impl.encoding.CodeSetConversion;
import com.sun.corba.se.impl.util.Utility;
import com.sun.corba.se.impl.util.RepositoryId;
import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
import com.sun.corba.se.impl.orbutil.RepositoryIdInterface;
import com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.CacheTable;
import com.sun.org.omg.CORBA.portable.ValueHelper;
import com.sun.org.omg.SendingContext.CodeBase;
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 = (CDRInputStreamBase)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();
repIdStrs = RepositoryIdFactory.getRepIdStringsFactory();
}
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,
// we 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-IIOP
// Serializable'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) {
int nextLong = read_long();
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
if (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)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);
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());
}
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)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 iff StubAdapter.isStubClass( clz ).
// In addition, clz is a IDL stub class iff
// 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, (Class)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)orb, CORBALogDomains.RPC_ENCODING ) ;
java.lang.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 java.lang.Object read_abstract_interface()
{
return read_abstract_interface(null);
}
public java.lang.Object read_abstract_interface(java.lang.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);
java.lang.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();
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);
java.lang.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(java.lang.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);
java.lang.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(java.lang.String.class);
classRepId = (String)read_value(java.lang.String.class);
} else {
// Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID
// and codebase strings in the wrong order.
classRepId = (String)read_value(java.lang.String.class);
codebases = (String)read_value(java.lang.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 java.lang.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
java.lang.Object result = helper.read_value(parent);
return result;
}
// found two-argument read method, so must be non-boxed value...
// ...create a blank instance
java.lang.Object val = null;
try {
val = helper.get_class().newInstance();
} catch(java.lang.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 {
java.lang.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 java.lang.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 = (Method)AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public java.lang.Object run() throws NoSuchMethodException {
return helperClass.getDeclaredMethod(kReadMethod, argTypes);
}
}
);
} catch (PrivilegedActionException pae) {
// this gets caught below
throw (NoSuchMethodException)pae.getException();
}
java.lang.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 java.lang.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 java.lang.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 = (int)((doubleDigit & 0xf0) >> 4);
secondDigit = (int)(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 (String[])_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 java.lang.Object createStreamMemento() {
return new StreamMemento();
}
public void restoreInternalState(java.lang.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 ) ;
}
}
/**
* Attempts to find the class described by the given
* repository ID string. At most, three attempts are made:
* Try to find it locally, through the provided URL, and
* finally, via a URL from the remote CodeBase.
*/
private Class getClassFromString(String repositoryIDString,
String codebaseURL)
{
RepositoryIdInterface repositoryID
= repIdStrs.getFromString(repositoryIDString);
for (int i = 0; i < 3; i++) {
try {
switch (i)
{
case 0:
// First try to load the class locally
return repositoryID.getClassFromType();
case 1:
// Try to load the class using the provided
// codebase URL (falls out below)
break;
case 2:
// Try to load the class using a URL from the
// remote CodeBase
codebaseURL = getCodeBase().implementation(repositoryIDString);
break;
}
// Don't bother if the codebaseURL is null
if (codebaseURL == null)
continue;
return repositoryID.getClassFromType(codebaseURL);
} catch(ClassNotFoundException cnfe) {
// Will ultimately return null if all three
// attempts fail, but don't do anything here.
} catch (MalformedURLException mue) {
throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
mue, repositoryIDString, codebaseURL ) ;
}
}
// If we get here, we have failed to load the class
dprint("getClassFromString failed with rep id "
+ repositoryIDString
+ " and codebase "
+ codebaseURL);
return null;
}
// 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)
{
MessageMediator messageMediator = parent.getMessageMediator();
if (messageMediator != null)
{
CDROutputObject outputObj =
(CDROutputObject)messageMediator.getOutputObject();
if (outputObj != null)
{
if (outputObj.isSharing(getByteBuffer()))
{
// 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;
}
}
}