| /* |
| * 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; |
| } |
| } |
| } |