CDRInputStream_1_0.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * Licensed Materials - Property of IBM
28 * RMI-IIOP v1.0
29 * Copyright IBM Corp. 1998 1999  All Rights Reserved
30 *
31 */
32
33package com.sun.corba.se.impl.encoding;
34
35import java.io.IOException;
36import java.io.Serializable;
37import java.io.ByteArrayInputStream;
38import java.io.ObjectInputStream;
39import java.io.IOException;
40import java.io.StreamCorruptedException;
41import java.io.OptionalDataException;
42import java.io.IOException;
43
44import java.util.Stack;
45
46import java.net.URL;
47import java.net.MalformedURLException;
48
49import java.nio.ByteBuffer;
50
51import java.lang.reflect.InvocationTargetException;
52import java.lang.reflect.Method;
53
54import java.math.BigDecimal;
55
56import java.rmi.Remote;
57import java.rmi.StubNotFoundException;
58
59import java.security.AccessController;
60import java.security.PrivilegedExceptionAction;
61import java.security.PrivilegedActionException;
62
63import org.omg.CORBA.SystemException;
64import org.omg.CORBA.Object;
65import org.omg.CORBA.Principal;
66import org.omg.CORBA.TypeCode;
67import org.omg.CORBA.Any;
68import org.omg.CORBA.portable.Delegate;
69import org.omg.CORBA.portable.ValueBase;
70import org.omg.CORBA.portable.IndirectionException;
71import org.omg.CORBA.CompletionStatus;
72import org.omg.CORBA.TCKind;
73import org.omg.CORBA.TypeCodePackage.BadKind;
74import org.omg.CORBA.CustomMarshal;
75import org.omg.CORBA.TypeCode;
76import org.omg.CORBA.Principal;
77import org.omg.CORBA.Any;
78import org.omg.CORBA.portable.BoxedValueHelper;
79import org.omg.CORBA.portable.ValueFactory;
80import org.omg.CORBA.portable.CustomValue;
81import org.omg.CORBA.portable.StreamableValue;
82import org.omg.CORBA.MARSHAL;
83import org.omg.CORBA.portable.IDLEntity;
84
85import javax.rmi.PortableRemoteObject;
86import javax.rmi.CORBA.Tie;
87import javax.rmi.CORBA.Util;
88import javax.rmi.CORBA.ValueHandler;
89
90import com.sun.corba.se.pept.protocol.MessageMediator;
91import com.sun.corba.se.pept.transport.ByteBufferPool;
92
93import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
94import com.sun.corba.se.spi.protocol.CorbaClientDelegate;
95
96import com.sun.corba.se.spi.ior.IOR;
97import com.sun.corba.se.spi.ior.IORFactories;
98import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
99
100import com.sun.corba.se.spi.orb.ORB;
101import com.sun.corba.se.spi.orb.ORBVersionFactory;
102import com.sun.corba.se.spi.orb.ORBVersion;
103
104import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
105
106import com.sun.corba.se.spi.logging.CORBALogDomains;
107import com.sun.corba.se.spi.presentation.rmi.PresentationManager;
108import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
109import com.sun.corba.se.spi.presentation.rmi.PresentationDefaults;
110
111import com.sun.corba.se.impl.logging.ORBUtilSystemException;
112import com.sun.corba.se.impl.logging.OMGSystemException;
113
114import com.sun.corba.se.impl.corba.PrincipalImpl;
115import com.sun.corba.se.impl.corba.TypeCodeImpl;
116import com.sun.corba.se.impl.corba.CORBAObjectImpl;
117
118import com.sun.corba.se.impl.encoding.CDROutputObject;
119import com.sun.corba.se.impl.encoding.CodeSetConversion;
120
121import com.sun.corba.se.impl.util.Utility;
122import com.sun.corba.se.impl.util.RepositoryId;
123
124import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
125import com.sun.corba.se.impl.orbutil.RepositoryIdInterface;
126import com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
127import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
128
129import com.sun.corba.se.impl.orbutil.ORBUtility;
130import com.sun.corba.se.impl.orbutil.CacheTable;
131
132
133import com.sun.org.omg.CORBA.portable.ValueHelper;
134
135import com.sun.org.omg.SendingContext.CodeBase;
136
137public class CDRInputStream_1_0 extends CDRInputStreamBase
138    implements RestorableInputStream
139{
140    private static final String kReadMethod = "read";
141    private static final int maxBlockLength = 0x7fffff00;
142
143    protected BufferManagerRead bufferManagerRead;
144    protected ByteBufferWithInfo bbwi;
145
146    // Set to the ORB's transportDebugFlag value.  This value is
147    // used if the ORB is null.
148    private boolean debug = false;
149
150    protected boolean littleEndian;
151    protected ORB orb;
152    protected ORBUtilSystemException wrapper ;
153    protected OMGSystemException omgWrapper ;
154    protected ValueHandler valueHandler = null;
155
156    // Value cache
157    private CacheTable valueCache = null;
158
159    // Repository ID cache
160    private CacheTable repositoryIdCache = null;
161
162    // codebase cache
163    private CacheTable codebaseCache = null;
164
165    // Current Class Stack (repository Ids of current class being read)
166    // private Stack currentStack = null;
167
168    // Length of current chunk, or a large positive number if not in a chunk
169    protected int blockLength = maxBlockLength;
170
171    // Read end flag (value nesting depth)
172    protected int end_flag = 0;
173
174    // Beginning with the resolution to interop issue 3526 (4328?),
175    // only enclosing chunked valuetypes are taken into account
176    // when computing the nesting level.  However, we still need
177    // the old computation around for interoperability with our
178    // older ORBs.
179    private int chunkedValueNestingLevel = 0;
180
181    // Flag used to determine whether blocksize was zero
182    // private int checkForNullBlock = -1;
183
184    // In block flag
185    // private boolean inBlock = false;
186
187    // Indicates whether we are inside a value
188    // private boolean outerValueDone = true;
189
190    // Int used by read_value(Serializable) that is set by this class
191    // before calling ValueFactory.read_value
192    protected int valueIndirection = 0;
193
194    // Int set by readStringOrIndirection to communicate the actual
195    // offset of the string length field back to the caller
196    protected int stringIndirection = 0;
197
198    // Flag indicating whether we are unmarshalling a chunked value
199    protected boolean isChunked = false;
200
201    // Repository ID handlers
202    private RepositoryIdUtility repIdUtil;
203    private RepositoryIdStrings repIdStrs;
204
205    // Code set converters (created when first needed)
206    private CodeSetConversion.BTCConverter charConverter;
207    private CodeSetConversion.BTCConverter wcharConverter;
208
209    // RMI-IIOP stream format version 2 case in which we know
210    // that there is no more optional data available.  If the
211    // Serializable's readObject method tries to read anything,
212    // we must throw a MARSHAL with the special minor code
213    // so that the ValueHandler can give the correct exception
214    // to readObject.  The state is cleared when the ValueHandler
215    // calls end_value after the readObject method exits.
216    private boolean specialNoOptionalDataState = false;
217
218    // Template method
219    public CDRInputStreamBase dup()
220    {
221        CDRInputStreamBase result = null ;
222
223        try {
224            result = (CDRInputStreamBase)this.getClass().newInstance();
225        } catch (Exception e) {
226            throw wrapper.couldNotDuplicateCdrInputStream( e ) ;
227        }
228        result.init(this.orb,
229                    this.bbwi.byteBuffer,
230                    this.bbwi.buflen,
231                    this.littleEndian,
232                    this.bufferManagerRead);
233
234        ((CDRInputStream_1_0)result).bbwi.position(this.bbwi.position());
235        // To ensure we keep bbwi.byteBuffer.limit in sync with bbwi.buflen.
236        ((CDRInputStream_1_0)result).bbwi.byteBuffer.limit(this.bbwi.buflen);
237
238        return result;
239    }
240
241    /**
242     * NOTE:  size passed to init means buffer size
243     */
244    public void init(org.omg.CORBA.ORB orb,
245                     ByteBuffer byteBuffer,
246                     int size,
247                     boolean littleEndian,
248                     BufferManagerRead bufferManager)
249    {
250        this.orb = (ORB)orb;
251        this.wrapper = ORBUtilSystemException.get( (ORB)orb,
252            CORBALogDomains.RPC_ENCODING ) ;
253        this.omgWrapper = OMGSystemException.get( (ORB)orb,
254            CORBALogDomains.RPC_ENCODING ) ;
255        this.littleEndian = littleEndian;
256        this.bufferManagerRead = bufferManager;
257        this.bbwi = new ByteBufferWithInfo(orb,byteBuffer,0);
258        this.bbwi.buflen = size;
259        this.bbwi.byteBuffer.limit(bbwi.buflen);
260        this.markAndResetHandler = bufferManagerRead.getMarkAndResetHandler();
261
262        debug = ((ORB)orb).transportDebugFlag;
263    }
264
265    // See description in CDRInputStream
266    void performORBVersionSpecificInit() {
267        createRepositoryIdHandlers();
268    }
269
270    private final void createRepositoryIdHandlers()
271    {
272        repIdUtil = RepositoryIdFactory.getRepIdUtility();
273        repIdStrs = RepositoryIdFactory.getRepIdStringsFactory();
274    }
275
276    public GIOPVersion getGIOPVersion() {
277        return GIOPVersion.V1_0;
278    }
279
280    // Called by Request and Reply message. Valid for GIOP versions >= 1.2 only.
281    // Illegal for GIOP versions < 1.2.
282    void setHeaderPadding(boolean headerPadding) {
283        throw wrapper.giopVersionError();
284    }
285
286    protected final int computeAlignment(int index, int align) {
287        if (align > 1) {
288            int incr = index & (align - 1);
289            if (incr != 0)
290                return align - incr;
291        }
292
293        return 0;
294    }
295
296    public int getSize()
297    {
298        return bbwi.position();
299    }
300
301    protected void checkBlockLength(int align, int dataSize) {
302        // Since chunks can end at arbitrary points (though not within
303        // primitive CDR types, arrays of primitives, strings, wstrings,
304        // or indirections),
305        // we must check here for termination of the current chunk.
306        if (!isChunked)
307            return;
308
309        // RMI-IIOP stream format version 2 case in which we know
310        // that there is no more optional data available.  If the
311        // Serializable's readObject method tries to read anything,
312        // we must throw a MARSHAL exception with the special minor code
313        // so that the ValueHandler can give the correct exception
314        // to readObject.  The state is cleared when the ValueHandler
315        // calls end_value after the readObject method exits.
316        if (specialNoOptionalDataState) {
317            throw omgWrapper.rmiiiopOptionalDataIncompatible1() ;
318        }
319
320        boolean checkForEndTag = false;
321
322        // Are we at the end of the current chunk?  If so,
323        // try to interpret the next long as a chunk length.
324        // (It has to be either a chunk length, end tag,
325        // or valuetag.)
326        //
327        // If it isn't a chunk length, blockLength will
328        // remain set to maxBlockLength.
329        if (blockLength == get_offset()) {
330
331            blockLength = maxBlockLength;
332            start_block();
333
334            // What's next is either a valuetag or
335            // an end tag.  If it's a valuetag, we're
336            // probably being called as part of the process
337            // to read the valuetag.  If it's an end tag,
338            // then there isn't enough data left in
339            // this valuetype to read!
340            if (blockLength == maxBlockLength)
341                checkForEndTag = true;
342
343        } else
344        if (blockLength < get_offset()) {
345            // Are we already past the end of the current chunk?
346            // This is always an error.
347            throw wrapper.chunkOverflow() ;
348        }
349
350        // If what's next on the wire isn't a chunk length or
351        // what we want to read (which can't be split across chunks)
352        // won't fit in the current chunk, throw this exception.
353        // This probably means that we're in an RMI-IIOP
354        // Serializable's readObject method or a custom marshaled
355        // IDL type is reading too much/in an incorrect order
356        int requiredNumBytes =
357                            computeAlignment(bbwi.position(), align) + dataSize;
358
359        if (blockLength != maxBlockLength &&
360            blockLength < get_offset() + requiredNumBytes) {
361            throw omgWrapper.rmiiiopOptionalDataIncompatible2() ;
362        }
363
364        // REVISIT - We should look at using the built in advancement
365        //           of using ByteBuffer.get() rather than explicitly
366        //           advancing the ByteBuffer's position.
367        //           This is true for anywhere we are incrementing
368        //           the ByteBuffer's position.
369        if (checkForEndTag) {
370            int nextLong = read_long();
371            bbwi.position(bbwi.position() - 4);
372
373            // It was an end tag, so there wasn't enough data
374            // left in the valuetype's encoding on the wire
375            // to read what we wanted
376            if (nextLong < 0)
377                throw omgWrapper.rmiiiopOptionalDataIncompatible3() ;
378        }
379    }
380
381    protected void alignAndCheck(int align, int n) {
382
383        checkBlockLength(align, n);
384
385        // WARNING: Must compute real alignment after calling
386        // checkBlockLength since it may move the position
387        int alignResult = computeAlignment(bbwi.position(), align);
388        bbwi.position(bbwi.position() + alignResult);
389
390        if (bbwi.position() + n > bbwi.buflen)
391            grow(align, n);
392    }
393
394    //
395    // This can be overridden....
396    //
397    protected void grow(int align, int n) {
398
399        bbwi.needed = n;
400
401        bbwi = bufferManagerRead.underflow(bbwi);
402
403    }
404
405    //
406    // Marshal primitives.
407    //
408
409    public final void consumeEndian() {
410        littleEndian = read_boolean();
411    }
412
413    // No such type in java
414    public final double read_longdouble() {
415        throw wrapper.longDoubleNotImplemented( CompletionStatus.COMPLETED_MAYBE);
416    }
417
418    public final boolean read_boolean() {
419        return (read_octet() != 0);
420    }
421
422    public final char read_char() {
423        alignAndCheck(1, 1);
424
425        return getConvertedChars(1, getCharConverter())[0];
426    }
427
428    public char read_wchar() {
429
430        // Don't allow transmission of wchar/wstring data with
431        // foreign ORBs since it's against the spec.
432        if (ORBUtility.isForeignORB((ORB)orb)) {
433            throw wrapper.wcharDataInGiop10( CompletionStatus.COMPLETED_MAYBE);
434        }
435
436        // If we're talking to one of our legacy ORBs, do what
437        // they did:
438        int b1, b2;
439
440        alignAndCheck(2, 2);
441
442        if (littleEndian) {
443            b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
444            bbwi.position(bbwi.position() + 1);
445            b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
446            bbwi.position(bbwi.position() + 1);
447        } else {
448            b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
449            bbwi.position(bbwi.position() + 1);
450            b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
451            bbwi.position(bbwi.position() + 1);
452        }
453
454        return (char)((b1 << 8) + (b2 << 0));
455    }
456
457    public final byte read_octet() {
458
459        alignAndCheck(1, 1);
460
461        byte b = bbwi.byteBuffer.get(bbwi.position());
462        bbwi.position(bbwi.position() + 1);
463
464        return b;
465    }
466
467    public final short read_short() {
468        int b1, b2;
469
470        alignAndCheck(2, 2);
471
472        if (littleEndian) {
473            b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
474            bbwi.position(bbwi.position() + 1);
475            b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
476            bbwi.position(bbwi.position() + 1);
477        } else {
478            b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
479            bbwi.position(bbwi.position() + 1);
480            b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
481            bbwi.position(bbwi.position() + 1);
482        }
483
484        return (short)(b1 | b2);
485    }
486
487    public final short read_ushort() {
488        return read_short();
489    }
490
491    public final int read_long() {
492        int b1, b2, b3, b4;
493
494        alignAndCheck(4, 4);
495
496        int bufPos = bbwi.position();
497        if (littleEndian) {
498            b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
499            b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
500            b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
501            b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
502        } else {
503            b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
504            b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
505            b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
506            b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
507        }
508        bbwi.position(bufPos);
509
510        return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
511    }
512
513    public final int read_ulong() {
514        return read_long();
515    }
516
517    public final long read_longlong() {
518        long i1, i2;
519
520        alignAndCheck(8, 8);
521
522        if (littleEndian) {
523            i2 = read_long() & 0xFFFFFFFFL;
524            i1 = (long)read_long() << 32;
525        } else {
526            i1 = (long)read_long() << 32;
527            i2 = read_long() & 0xFFFFFFFFL;
528        }
529
530        return (i1 | i2);
531    }
532
533    public final long read_ulonglong() {
534        return read_longlong();
535    }
536
537    public final float read_float() {
538        return Float.intBitsToFloat(read_long());
539    }
540
541    public final double read_double() {
542        return Double.longBitsToDouble(read_longlong());
543    }
544
545    protected final void checkForNegativeLength(int length) {
546        if (length < 0)
547            throw wrapper.negativeStringLength( CompletionStatus.COMPLETED_MAYBE,
548                new Integer(length) ) ;
549    }
550
551    protected final String readStringOrIndirection(boolean allowIndirection) {
552
553        int len = read_long();
554
555        //
556        // Check for indirection
557        //
558        if (allowIndirection) {
559            if (len == 0xffffffff)
560                return null;
561            else
562                stringIndirection = get_offset() - 4;
563        }
564
565        checkForNegativeLength(len);
566
567        return internalReadString(len);
568    }
569
570    private final String internalReadString(int len) {
571        // Workaround for ORBs which send string lengths of
572        // zero to mean empty string.
573        //
574        // IMPORTANT: Do not replace 'new String("")' with "", it may result
575        // in a Serialization bug (See serialization.zerolengthstring) and
576        // bug id: 4728756 for details
577        if (len == 0)
578            return new String("");
579
580        char[] result = getConvertedChars(len - 1, getCharConverter());
581
582        // Skip over the 1 byte null
583        read_octet();
584
585        return new String(result, 0, getCharConverter().getNumChars());
586    }
587
588    public final String read_string() {
589        return readStringOrIndirection(false);
590    }
591
592    public String read_wstring() {
593        // Don't allow transmission of wchar/wstring data with
594        // foreign ORBs since it's against the spec.
595        if (ORBUtility.isForeignORB((ORB)orb)) {
596            throw wrapper.wcharDataInGiop10( CompletionStatus.COMPLETED_MAYBE);
597        }
598
599        int len = read_long();
600
601        //
602        // Workaround for ORBs which send string lengths of
603        // zero to mean empty string.
604        //
605        //
606        // IMPORTANT: Do not replace 'new String("")' with "", it may result
607        // in a Serialization bug (See serialization.zerolengthstring) and
608        // bug id: 4728756 for details
609        if (len == 0)
610            return new String("");
611
612        checkForNegativeLength(len);
613
614        len--;
615        char[] c = new char[len];
616
617        for (int i = 0; i < len; i++)
618            c[i] = read_wchar();
619
620        // skip the two null terminator bytes
621        read_wchar();
622        // bbwi.position(bbwi.position() + 2);
623
624        return new String(c);
625    }
626
627    public final void read_octet_array(byte[] b, int offset, int length) {
628        if ( b == null )
629            throw wrapper.nullParam() ;
630
631        // Must call alignAndCheck at least once to ensure
632        // we aren't at the end of a chunk.  Of course, we
633        // should only call it if we actually need to read
634        // something, otherwise we might end up with an
635        // exception at the end of the stream.
636        if (length == 0)
637            return;
638
639        alignAndCheck(1, 1);
640
641        int n = offset;
642        while (n < length+offset) {
643            int avail;
644            int bytes;
645            int wanted;
646
647            avail = bbwi.buflen - bbwi.position();
648            if (avail <= 0) {
649                grow(1, 1);
650                avail = bbwi.buflen - bbwi.position();
651            }
652            wanted = (length + offset) - n;
653            bytes = (wanted < avail) ? wanted : avail;
654            // Microbenchmarks are showing a loop of ByteBuffer.get(int) being
655            // faster than ByteBuffer.get(byte[], int, int).
656            for (int i = 0; i < bytes; i++) {
657                b[n+i] = bbwi.byteBuffer.get(bbwi.position() + i);
658            }
659
660            bbwi.position(bbwi.position() + bytes);
661
662            n += bytes;
663        }
664    }
665
666    public Principal read_Principal() {
667        int len = read_long();
668        byte[] pvalue = new byte[len];
669        read_octet_array(pvalue,0,len);
670
671        Principal p = new PrincipalImpl();
672        p.name(pvalue);
673        return p;
674    }
675
676    public TypeCode read_TypeCode() {
677        TypeCodeImpl tc = new TypeCodeImpl(orb);
678        tc.read_value(parent);
679        return tc;
680    }
681
682    public Any read_any() {
683        Any any = orb.create_any();
684        TypeCodeImpl tc = new TypeCodeImpl(orb);
685
686        // read off the typecode
687
688        // REVISIT We could avoid this try-catch if we could peek the typecode
689        // kind off this stream and see if it is a tk_value.  Looking at the
690        // code we know that for tk_value the Any.read_value() below
691        // ignores the tc argument anyway (except for the kind field).
692        // But still we would need to make sure that the whole typecode,
693        // including encapsulations, is read off.
694        try {
695            tc.read_value(parent);
696        } catch (MARSHAL ex) {
697            if (tc.kind().value() != TCKind._tk_value)
698                throw ex;
699            // We can be sure that the whole typecode encapsulation has been
700            // read off.
701            dprintThrowable(ex);
702        }
703        // read off the value of the any
704        any.read_value(parent, tc);
705
706        return any;
707    }
708
709    public org.omg.CORBA.Object read_Object() {
710        return read_Object(null);
711    }
712
713    // ------------ RMI related methods --------------------------
714
715    // IDL to Java ptc-00-01-08 1.21.4.1
716    //
717    // The clz argument to read_Object can be either a stub
718    // Class or the "Class object for the RMI/IDL interface type
719    // that is statically expected."
720    // This functions as follows:
721    // 1. If clz==null, just use the repository ID from the stub
722    // 2. If clz is a stub class, just use it as a static factory.
723    //    clz is a stub class iff StubAdapter.isStubClass( clz ).
724    //    In addition, clz is a IDL stub class iff
725    //    IDLEntity.class.isAssignableFrom( clz ).
726    // 3. If clz is an interface, use it to create the appropriate
727    //    stub factory.
728    public org.omg.CORBA.Object read_Object(Class clz)
729    {
730        // In any case, we must first read the IOR.
731        IOR ior = IORFactories.makeIOR(parent) ;
732        if (ior.isNil())
733            return null ;
734
735        PresentationManager.StubFactoryFactory sff = ORB.getStubFactoryFactory() ;
736        String codeBase = ior.getProfile().getCodebase() ;
737        PresentationManager.StubFactory stubFactory = null ;
738
739        if (clz == null) {
740            RepositoryId rid = RepositoryId.cache.getId( ior.getTypeId() ) ;
741            String className = rid.getClassName() ;
742            boolean isIDLInterface = rid.isIDLType() ;
743
744            if (className == null || className.equals( "" ))
745                stubFactory = null ;
746            else
747                try {
748                    stubFactory = sff.createStubFactory( className,
749                        isIDLInterface, codeBase, (Class)null,
750                        (ClassLoader)null );
751                } catch (Exception exc) {
752                    // Could not create stubFactory, so use null.
753                    // XXX stubFactory handling is still too complex:
754                    // Can we resolve the stubFactory question once in
755                    // a single place?
756                    stubFactory = null ;
757                }
758        } else if (StubAdapter.isStubClass( clz )) {
759            stubFactory = PresentationDefaults.makeStaticStubFactory(
760                clz ) ;
761        } else {
762            // clz is an interface class
763            boolean isIDL = IDLEntity.class.isAssignableFrom( clz ) ;
764
765            stubFactory = sff.createStubFactory( clz.getName(),
766                isIDL, codeBase, clz, clz.getClassLoader() ) ;
767        }
768
769        return internalIORToObject( ior, stubFactory, orb ) ;
770    }
771
772    /*
773     * This is used as a general utility (e.g., the PortableInterceptor
774     * implementation uses it.   If stubFactory is null, the ior's
775     * IIOPProfile must support getServant.
776     */
777    public static org.omg.CORBA.Object internalIORToObject(
778        IOR ior, PresentationManager.StubFactory stubFactory, ORB orb)
779    {
780        ORBUtilSystemException wrapper = ORBUtilSystemException.get(
781            (ORB)orb, CORBALogDomains.RPC_ENCODING ) ;
782
783        java.lang.Object servant = ior.getProfile().getServant() ;
784        if (servant != null ) {
785            if (servant instanceof Tie) {
786                String codebase = ior.getProfile().getCodebase();
787                org.omg.CORBA.Object objref = (org.omg.CORBA.Object)
788                    Utility.loadStub( (Tie)servant, stubFactory, codebase,
789                        false);
790
791                // If we managed to load a stub, return it, otherwise we
792                // must fail...
793                if (objref != null) {
794                    return objref;
795                } else {
796                    throw wrapper.readObjectException() ;
797                }
798            } else if (servant instanceof org.omg.CORBA.Object) {
799                if (!(servant instanceof
800                        org.omg.CORBA.portable.InvokeHandler)) {
801                    return (org.omg.CORBA.Object) servant;
802                }
803            } else
804                throw wrapper.badServantReadObject() ;
805        }
806
807        CorbaClientDelegate del = ORBUtility.makeClientDelegate( ior ) ;
808        org.omg.CORBA.Object objref = null ;
809        try {
810            objref = stubFactory.makeStub() ;
811        } catch (Throwable e) {
812            wrapper.stubCreateError( e ) ;
813
814            if (e instanceof ThreadDeath) {
815                throw (ThreadDeath) e;
816            }
817
818            // Return the "default" stub...
819            objref = new CORBAObjectImpl() ;
820        }
821
822        StubAdapter.setDelegate( objref, del ) ;
823        return objref;
824    }
825
826    public java.lang.Object read_abstract_interface()
827    {
828        return read_abstract_interface(null);
829    }
830
831    public java.lang.Object read_abstract_interface(java.lang.Class clz)
832    {
833        boolean object = read_boolean();
834
835        if (object) {
836            return read_Object(clz);
837        } else {
838            return read_value();
839        }
840    }
841
842    public Serializable read_value()
843    {
844        return read_value((Class)null);
845    }
846
847    private Serializable handleIndirection() {
848        int indirection = read_long() + get_offset() - 4;
849        if (valueCache != null && valueCache.containsVal(indirection)) {
850
851            java.io.Serializable cachedValue
852                = (java.io.Serializable)valueCache.getKey(indirection);
853            return cachedValue;
854        } else {
855            // In RMI-IIOP the ValueHandler will recognize this
856            // exception and use the provided indirection value
857            // to lookup a possible indirection to an object
858            // currently on the deserialization stack.
859            throw new IndirectionException(indirection);
860        }
861    }
862
863    private String readRepositoryIds(int valueTag,
864                                     Class expectedType,
865                                     String expectedTypeRepId) {
866        return readRepositoryIds(valueTag, expectedType,
867                                 expectedTypeRepId, null);
868    }
869
870    /**
871     * Examines the valuetag to see how many (if any) repository IDs
872     * are present on the wire.  If no repository ID information
873     * is on the wire but the expectedType or expectedTypeRepId
874     * is known, it will return one of those (favoring the
875     * expectedType's repId). Failing that, it uses the supplied
876     * BoxedValueHelper to obtain the repository ID, as a last resort.
877     */
878    private String readRepositoryIds(int valueTag,
879                                     Class expectedType,
880                                     String expectedTypeRepId,
881                                     BoxedValueHelper factory) {
882        switch(repIdUtil.getTypeInfo(valueTag)) {
883            case RepositoryIdUtility.NO_TYPE_INFO :
884                // Throw an exception if we have no repository ID info and
885                // no expectedType to work with.  Otherwise, how would we
886                // know what to unmarshal?
887                if (expectedType == null) {
888                    if (expectedTypeRepId != null) {
889                        return expectedTypeRepId;
890                    } else if (factory != null) {
891                        return factory.get_id();
892                    } else {
893                        throw wrapper.expectedTypeNullAndNoRepId(
894                            CompletionStatus.COMPLETED_MAYBE);
895                    }
896                }
897                return repIdStrs.createForAnyType(expectedType);
898            case RepositoryIdUtility.SINGLE_REP_TYPE_INFO :
899                return read_repositoryId();
900            case RepositoryIdUtility.PARTIAL_LIST_TYPE_INFO :
901                return read_repositoryIds();
902            default:
903                throw wrapper.badValueTag( CompletionStatus.COMPLETED_MAYBE,
904                    Integer.toHexString(valueTag) ) ;
905        }
906    }
907
908    public Serializable read_value(Class expectedType) {
909
910        // Read value tag
911        int vType = readValueTag();
912
913        // Is value null?
914        if (vType == 0)
915            return null;
916
917        // Is this an indirection to a previously
918        // read valuetype?
919        if (vType == 0xffffffff)
920            return handleIndirection();
921
922        // Save where this valuetype started so we
923        // can put it in the indirection valueCache
924        // later
925        int indirection = get_offset() - 4;
926
927        // Need to save this special marker variable
928        // to restore its value during recursion
929        boolean saveIsChunked = isChunked;
930
931        isChunked = repIdUtil.isChunkedEncoding(vType);
932
933        java.lang.Object value = null;
934
935        String codebase_URL = null;
936        if (repIdUtil.isCodeBasePresent(vType)) {
937            codebase_URL = read_codebase_URL();
938        }
939
940        // Read repository id(s)
941        String repositoryIDString
942            = readRepositoryIds(vType, expectedType, null);
943
944        // If isChunked was determined to be true based
945        // on the valuetag, this will read a chunk length
946        start_block();
947
948        // Remember that end_flag keeps track of all nested
949        // valuetypes and is used for older ORBs
950        end_flag--;
951        if (isChunked)
952            chunkedValueNestingLevel--;
953
954        if (repositoryIDString.equals(repIdStrs.getWStringValueRepId())) {
955            value = read_wstring();
956        } else
957        if (repositoryIDString.equals(repIdStrs.getClassDescValueRepId())) {
958            // read in the class whether with the old ClassDesc or the
959            // new one
960            value = readClass();
961        } else {
962
963            Class valueClass = expectedType;
964
965            // By this point, either the expectedType or repositoryIDString
966            // is guaranteed to be non-null.
967            if (expectedType == null ||
968                !repositoryIDString.equals(repIdStrs.createForAnyType(expectedType))) {
969
970                valueClass = getClassFromString(repositoryIDString,
971                                                codebase_URL,
972                                                expectedType);
973            }
974
975            if (valueClass == null) {
976                // No point attempting to use value handler below, since the
977                // class information is not available.
978                throw wrapper.couldNotFindClass(
979                    CompletionStatus.COMPLETED_MAYBE,
980                    new ClassNotFoundException());
981            }
982
983            if (valueClass != null &&
984                org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(valueClass)) {
985
986                value =  readIDLValue(indirection,
987                                      repositoryIDString,
988                                      valueClass,
989                                      codebase_URL);
990
991            } else {
992
993                // Must be some form of RMI-IIOP valuetype
994
995                try {
996                    if (valueHandler == null)
997                        valueHandler = ORBUtility.createValueHandler();
998
999                    value = valueHandler.readValue(parent,
1000                                                   indirection,
1001                                                   valueClass,
1002                                                   repositoryIDString,
1003                                                   getCodeBase());
1004
1005                } catch(SystemException sysEx) {
1006                    // Just rethrow any CORBA system exceptions
1007                    // that come out of the ValueHandler
1008                    throw sysEx;
1009                } catch(Exception ex) {
1010                    throw wrapper.valuehandlerReadException(
1011                        CompletionStatus.COMPLETED_MAYBE, ex ) ;
1012                } catch(Error e) {
1013                    throw wrapper.valuehandlerReadError(
1014                        CompletionStatus.COMPLETED_MAYBE, e ) ;
1015                }
1016            }
1017        }
1018
1019        // Skip any remaining chunks until we get to
1020        // an end tag or a valuetag.  If we see a valuetag,
1021        // that means there was another valuetype in the sender's
1022        // version of this class that we need to skip over.
1023        handleEndOfValue();
1024
1025        // Read and process the end tag if we're chunking.
1026        // Assumes that we're at the position of the end tag
1027        // (handleEndOfValue should assure this)
1028        readEndTag();
1029
1030        // Cache the valuetype that we read
1031        if (valueCache == null)
1032            valueCache = new CacheTable(orb,false);
1033        valueCache.put(value, indirection);
1034
1035        // Allow for possible continuation chunk.
1036        // If we're a nested valuetype inside of a chunked
1037        // valuetype, and that enclosing valuetype has
1038        // more data to write, it will need to have this
1039        // new chunk begin after we wrote our end tag.
1040        isChunked = saveIsChunked;
1041        start_block();
1042
1043        return (java.io.Serializable)value;
1044    }
1045
1046    public Serializable read_value(BoxedValueHelper factory) {
1047
1048        // Read value tag
1049        int vType = readValueTag();
1050
1051        if (vType == 0)
1052            return null; // value is null
1053        else if (vType == 0xffffffff) { // Indirection tag
1054            int indirection = read_long() + get_offset() - 4;
1055            if (valueCache != null && valueCache.containsVal(indirection))
1056                {
1057                    java.io.Serializable cachedValue =
1058                           (java.io.Serializable)valueCache.getKey(indirection);
1059                    return cachedValue;
1060                }
1061            else {
1062                throw new IndirectionException(indirection);
1063            }
1064        }
1065        else {
1066            int indirection = get_offset() - 4;
1067
1068            // end_block();
1069
1070            boolean saveIsChunked = isChunked;
1071            isChunked = repIdUtil.isChunkedEncoding(vType);
1072
1073            java.lang.Object value = null;
1074
1075            String codebase_URL = null;
1076            if (repIdUtil.isCodeBasePresent(vType)){
1077                codebase_URL = read_codebase_URL();
1078            }
1079
1080            // Read repository id
1081            String repositoryIDString
1082                = readRepositoryIds(vType, null, null, factory);
1083
1084            // Compare rep. ids to see if we should use passed helper
1085            if (!repositoryIDString.equals(factory.get_id()))
1086                factory = Utility.getHelper(null, codebase_URL, repositoryIDString);
1087
1088            start_block();
1089            end_flag--;
1090            if (isChunked)
1091                chunkedValueNestingLevel--;
1092
1093            if (factory instanceof ValueHelper) {
1094                value = readIDLValueWithHelper((ValueHelper)factory, indirection);
1095            } else {
1096                valueIndirection = indirection;  // for callback
1097                value = factory.read_value(parent);
1098            }
1099
1100            handleEndOfValue();
1101            readEndTag();
1102
1103            // Put into valueCache
1104            if (valueCache == null)
1105                valueCache = new CacheTable(orb,false);
1106            valueCache.put(value, indirection);
1107
1108            // allow for possible continuation chunk
1109            isChunked = saveIsChunked;
1110            start_block();
1111
1112            return (java.io.Serializable)value;
1113        }
1114    }
1115
1116    private boolean isCustomType(ValueHelper helper) {
1117        try{
1118            TypeCode tc = helper.get_type();
1119            int kind = tc.kind().value();
1120            if (kind == TCKind._tk_value) {
1121                return (tc.type_modifier() == org.omg.CORBA.VM_CUSTOM.value);
1122            }
1123        } catch(BadKind ex) {
1124            throw wrapper.badKind(ex) ;
1125        }
1126
1127        return false;
1128    }
1129
1130    // This method is actually called indirectly by
1131    // read_value(String repositoryId).
1132    // Therefore, it is not a truly independent read call that handles
1133    // header information itself.
1134    public java.io.Serializable read_value(java.io.Serializable value) {
1135
1136        // Put into valueCache using valueIndirection
1137        if (valueCache == null)
1138            valueCache = new CacheTable(orb,false);
1139        valueCache.put(value, valueIndirection);
1140
1141        if (value instanceof StreamableValue)
1142            ((StreamableValue)value)._read(parent);
1143        else if (value instanceof CustomValue)
1144            ((CustomValue)value).unmarshal(parent);
1145
1146        return value;
1147    }
1148
1149    public java.io.Serializable read_value(java.lang.String repositoryId) {
1150
1151        // if (inBlock)
1152        //    end_block();
1153
1154        // Read value tag
1155        int vType = readValueTag();
1156
1157        if (vType == 0)
1158            return null; // value is null
1159        else if (vType == 0xffffffff) { // Indirection tag
1160            int indirection = read_long() + get_offset() - 4;
1161            if (valueCache != null && valueCache.containsVal(indirection))
1162                {
1163                    java.io.Serializable cachedValue =
1164                          (java.io.Serializable)valueCache.getKey(indirection);
1165                    return cachedValue;
1166                }
1167            else {
1168                throw new IndirectionException(indirection);
1169            }
1170        }
1171        else {
1172            int indirection = get_offset() - 4;
1173
1174            // end_block();
1175
1176            boolean saveIsChunked = isChunked;
1177            isChunked = repIdUtil.isChunkedEncoding(vType);
1178
1179            java.lang.Object value = null;
1180
1181            String codebase_URL = null;
1182            if (repIdUtil.isCodeBasePresent(vType)){
1183                codebase_URL = read_codebase_URL();
1184            }
1185
1186            // Read repository id
1187            String repositoryIDString
1188                = readRepositoryIds(vType, null, repositoryId);
1189
1190            ValueFactory factory =
1191               Utility.getFactory(null, codebase_URL, orb, repositoryIDString);
1192
1193            start_block();
1194            end_flag--;
1195            if (isChunked)
1196                chunkedValueNestingLevel--;
1197
1198            valueIndirection = indirection;  // for callback
1199            value = factory.read_value(parent);
1200
1201            handleEndOfValue();
1202            readEndTag();
1203
1204            // Put into valueCache
1205            if (valueCache == null)
1206                valueCache = new CacheTable(orb,false);
1207            valueCache.put(value, indirection);
1208
1209            // allow for possible continuation chunk
1210            isChunked = saveIsChunked;
1211            start_block();
1212
1213            return (java.io.Serializable)value;
1214        }
1215    }
1216
1217    private Class readClass() {
1218
1219        String codebases = null, classRepId = null;
1220
1221        if (orb == null ||
1222            ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
1223            ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
1224
1225            codebases = (String)read_value(java.lang.String.class);
1226            classRepId = (String)read_value(java.lang.String.class);
1227        } else {
1228            // Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID
1229            // and codebase strings in the wrong order.
1230            classRepId = (String)read_value(java.lang.String.class);
1231            codebases = (String)read_value(java.lang.String.class);
1232        }
1233
1234        if (debug) {
1235            dprint("readClass codebases: "
1236                   + codebases
1237                   + " rep Id: "
1238                   + classRepId);
1239        }
1240
1241        Class cl = null;
1242
1243        RepositoryIdInterface repositoryID
1244            = repIdStrs.getFromString(classRepId);
1245
1246        try {
1247            cl = repositoryID.getClassFromType(codebases);
1248        } catch(ClassNotFoundException cnfe) {
1249            throw wrapper.cnfeReadClass( CompletionStatus.COMPLETED_MAYBE,
1250                cnfe, repositoryID.getClassName() ) ;
1251        } catch(MalformedURLException me) {
1252            throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
1253                me, repositoryID.getClassName(), codebases ) ;
1254        }
1255
1256        return cl;
1257    }
1258
1259    private java.lang.Object readIDLValueWithHelper(ValueHelper helper, int indirection)
1260    {
1261        // look for two-argument static read method
1262        Method readMethod;
1263        try {
1264            Class argTypes[] = {org.omg.CORBA.portable.InputStream.class, helper.get_class()};
1265            readMethod = helper.getClass().getDeclaredMethod(kReadMethod, argTypes);
1266        }
1267        catch(NoSuchMethodException nsme) { // must be boxed value helper
1268            java.lang.Object result = helper.read_value(parent);
1269            return result;
1270        }
1271
1272        // found two-argument read method, so must be non-boxed value...
1273        // ...create a blank instance
1274        java.lang.Object val = null;
1275        try {
1276            val = helper.get_class().newInstance();
1277        } catch(java.lang.InstantiationException ie) {
1278            throw wrapper.couldNotInstantiateHelper( ie,
1279                helper.get_class() ) ;
1280        } catch(IllegalAccessException iae){
1281            // Value's constructor is protected or private
1282            //
1283            // So, use the helper to read the value.
1284            //
1285            // NOTE : This means that in this particular case a recursive ref.
1286            // would fail.
1287            return helper.read_value(parent);
1288        }
1289
1290        // add blank instance to cache table
1291        if (valueCache == null)
1292            valueCache = new CacheTable(orb,false);
1293        valueCache.put(val, indirection);
1294
1295        // if custom type, call unmarshal method
1296        if (val instanceof CustomMarshal && isCustomType(helper)) {
1297            ((CustomMarshal)val).unmarshal(parent);
1298            return val;
1299        }
1300
1301        // call two-argument read method using reflection
1302        try {
1303            java.lang.Object args[] = {parent, val};
1304            readMethod.invoke(helper, args);
1305            return val;
1306        } catch(IllegalAccessException iae2) {
1307            throw wrapper.couldNotInvokeHelperReadMethod( iae2, helper.get_class() ) ;
1308        } catch(InvocationTargetException ite){
1309            throw wrapper.couldNotInvokeHelperReadMethod( ite, helper.get_class() ) ;
1310        }
1311    }
1312
1313    private java.lang.Object readBoxedIDLEntity(Class clazz, String codebase)
1314    {
1315        Class cls = null ;
1316
1317        try {
1318            ClassLoader clazzLoader = (clazz == null ? null : clazz.getClassLoader());
1319
1320            cls = Utility.loadClassForClass(clazz.getName()+"Helper", codebase,
1321                                                   clazzLoader, clazz, clazzLoader);
1322            final Class helperClass = cls ;
1323
1324            final Class argTypes[] = {org.omg.CORBA.portable.InputStream.class};
1325
1326            // getDeclaredMethod requires RuntimePermission accessDeclaredMembers
1327            // if a different class loader is used (even though the javadoc says otherwise)
1328            Method readMethod = null;
1329            try {
1330                readMethod = (Method)AccessController.doPrivileged(
1331                    new PrivilegedExceptionAction() {
1332                        public java.lang.Object run() throws NoSuchMethodException {
1333                            return helperClass.getDeclaredMethod(kReadMethod, argTypes);
1334                        }
1335                    }
1336                );
1337            } catch (PrivilegedActionException pae) {
1338                // this gets caught below
1339                throw (NoSuchMethodException)pae.getException();
1340            }
1341
1342            java.lang.Object args[] = {parent};
1343            return readMethod.invoke(null, args);
1344
1345        } catch (ClassNotFoundException cnfe) {
1346            throw wrapper.couldNotInvokeHelperReadMethod( cnfe, cls ) ;
1347        } catch(NoSuchMethodException nsme) {
1348            throw wrapper.couldNotInvokeHelperReadMethod( nsme, cls ) ;
1349        } catch(IllegalAccessException iae) {
1350            throw wrapper.couldNotInvokeHelperReadMethod( iae, cls ) ;
1351        } catch(InvocationTargetException ite) {
1352            throw wrapper.couldNotInvokeHelperReadMethod( ite, cls ) ;
1353        }
1354    }
1355
1356    private java.lang.Object readIDLValue(int indirection, String repId,
1357                                          Class clazz, String codebase)
1358    {
1359        ValueFactory factory ;
1360
1361        // Always try to find a ValueFactory first, as required by the spec.
1362        // There are some complications here in the IDL 3.0 mapping (see 1.13.8),
1363        // but basically we must always be able to override the DefaultFactory
1364        // or Helper mappings that are also used.  This appears to be the case
1365        // even in the boxed value cases.  The original code only did the lookup
1366        // in the case of class implementing either StreamableValue or CustomValue,
1367        // but abstract valuetypes only implement ValueBase, and really require
1368        // the use of the repId to find a factory (including the DefaultFactory).
1369        try {
1370            // use new-style OBV support (factory object)
1371            factory = Utility.getFactory(clazz, codebase, orb, repId);
1372        } catch (MARSHAL marshal) {
1373            // XXX log marshal at one of the INFO levels
1374
1375            // Could not get a factory, so try alternatives
1376            if (!StreamableValue.class.isAssignableFrom(clazz) &&
1377                !CustomValue.class.isAssignableFrom(clazz) &&
1378                ValueBase.class.isAssignableFrom(clazz)) {
1379                // use old-style OBV support (helper object)
1380                BoxedValueHelper helper = Utility.getHelper(clazz, codebase, repId);
1381                if (helper instanceof ValueHelper)
1382                    return readIDLValueWithHelper((ValueHelper)helper, indirection);
1383                else
1384                    return helper.read_value(parent);
1385            } else {
1386                // must be a boxed IDLEntity, so make a reflective call to the
1387                // helper's static read method...
1388                return readBoxedIDLEntity(clazz, codebase);
1389            }
1390        }
1391
1392        // If there was no error in getting the factory, use it.
1393        valueIndirection = indirection;  // for callback
1394        return factory.read_value(parent);
1395    }
1396
1397    /**
1398     * End tags are only written for chunked valuetypes.
1399     *
1400     * Before Merlin, our ORBs wrote end tags which took into account
1401     * all enclosing valuetypes.  This was changed by an interop resolution
1402     * (see details around chunkedValueNestingLevel) to only include
1403     * enclosing chunked types.
1404     *
1405     * ORB versioning and end tag compaction are handled here.
1406     */
1407    private void readEndTag() {
1408        if (isChunked) {
1409
1410            // Read the end tag
1411            int anEndTag = read_long();
1412
1413            // End tags should always be negative, and the outermost
1414            // enclosing chunked valuetype should have a -1 end tag.
1415            //
1416            // handleEndOfValue should have assured that we were
1417            // at the end tag position!
1418            if (anEndTag >= 0) {
1419                throw wrapper.positiveEndTag( CompletionStatus.COMPLETED_MAYBE,
1420                    new Integer(anEndTag), new Integer( get_offset() - 4 ) ) ;
1421            }
1422
1423            // If the ORB is null, or if we're sure we're talking to
1424            // a foreign ORB, Merlin, or something more recent, we
1425            // use the updated end tag computation, and are more strenuous
1426            // about the values.
1427            if (orb == null ||
1428                ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
1429                ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
1430
1431                // If the end tag we read was less than what we were expecting,
1432                // then the sender must think it's sent more enclosing
1433                // chunked valuetypes than we have.  Throw an exception.
1434                if (anEndTag < chunkedValueNestingLevel)
1435                    throw wrapper.unexpectedEnclosingValuetype(
1436                        CompletionStatus.COMPLETED_MAYBE, new Integer( anEndTag ),
1437                        new Integer( chunkedValueNestingLevel ) ) ;
1438
1439                // If the end tag is bigger than what we expected, but
1440                // still negative, then the sender has done some end tag
1441                // compaction.  We back up the stream 4 bytes so that the
1442                // next time readEndTag is called, it will get down here
1443                // again.  Even with fragmentation, we'll always be able
1444                // to do this.
1445                if (anEndTag != chunkedValueNestingLevel) {
1446                    bbwi.position(bbwi.position() - 4);
1447                 }
1448
1449            } else {
1450
1451                // When talking to Kestrel or Ladybird, we use our old
1452                // end tag rules and are less strict.  If the end tag
1453                // isn't what we expected, we back up, assuming
1454                // compaction.
1455                if (anEndTag != end_flag) {
1456                    bbwi.position(bbwi.position() - 4);
1457                }
1458            }
1459
1460            // This only keeps track of the enclosing chunked
1461            // valuetypes
1462            chunkedValueNestingLevel++;
1463        }
1464
1465        // This keeps track of all enclosing valuetypes
1466        end_flag++;
1467    }
1468
1469    protected int get_offset() {
1470        return bbwi.position();
1471    }
1472
1473    private void start_block() {
1474
1475        // if (outerValueDone)
1476        if (!isChunked)
1477            return;
1478
1479        // if called from alignAndCheck, need to reset blockLength
1480        // to avoid an infinite recursion loop on read_long() call
1481        blockLength = maxBlockLength;
1482
1483        blockLength = read_long();
1484
1485        // Must remember where we began the chunk to calculate how far
1486        // along we are.  See notes above about chunkBeginPos.
1487
1488        if (blockLength > 0 && blockLength < maxBlockLength) {
1489            blockLength += get_offset();  // _REVISIT_ unsafe, should use a Java long
1490
1491            // inBlock = true;
1492        } else {
1493
1494            // System.out.println("start_block snooped a " + Integer.toHexString(blockLength));
1495
1496            // not a chunk length field
1497            blockLength = maxBlockLength;
1498
1499            bbwi.position(bbwi.position() - 4);
1500        }
1501    }
1502
1503    // Makes sure that if we were reading a chunked value, we end up
1504    // at the right place in the stream, no matter how little the
1505    // unmarshalling code read.
1506    //
1507    // After calling this method, if we are chunking, we should be
1508    // in position to read the end tag.
1509    private void handleEndOfValue() {
1510
1511        // If we're not chunking, we don't have to worry about
1512        // skipping remaining chunks or finding end tags
1513        if (!isChunked)
1514            return;
1515
1516        // Skip any remaining chunks
1517        while (blockLength != maxBlockLength) {
1518            end_block();
1519            start_block();
1520        }
1521
1522        // Now look for the end tag
1523
1524        // This is a little wasteful since we're reading
1525        // this long up to 3 times in the worst cases (once
1526        // in start_block, once here, and once in readEndTag
1527        //
1528        // Peek next long
1529        int nextLong = read_long();
1530        bbwi.position(bbwi.position() - 4);
1531
1532        // We did find an end tag, so we're done.  readEndTag
1533        // should take care of making sure it's the correct
1534        // end tag, etc.  Remember that since end tags,
1535        // chunk lengths, and valuetags have non overlapping
1536        // ranges, we can tell by the value what the longs are.
1537        if (nextLong < 0)
1538            return;
1539
1540        if (nextLong == 0 || nextLong >= maxBlockLength) {
1541
1542            // A custom marshaled valuetype left extra data
1543            // on the wire, and that data had another
1544            // nested value inside of it.  We've just
1545            // read the value tag or null of that nested value.
1546            //
1547            // In an attempt to get by it, we'll try to call
1548            // read_value() to get the nested value off of
1549            // the wire.  Afterwards, we must call handleEndOfValue
1550            // recursively to read any further chunks that the containing
1551            // valuetype might still have after the nested
1552            // value.
1553            read_value();
1554            handleEndOfValue();
1555        } else {
1556            // This probably means that the code to skip chunks has
1557            // an error, and ended up setting blockLength to something
1558            // other than maxBlockLength even though we weren't
1559            // starting a new chunk.
1560            throw wrapper.couldNotSkipBytes( CompletionStatus.COMPLETED_MAYBE,
1561                new Integer( nextLong ), new Integer( get_offset() ) ) ;
1562        }
1563    }
1564
1565    private void end_block() {
1566
1567        // if in a chunk, check for underflow or overflow
1568        if (blockLength != maxBlockLength) {
1569            if (blockLength == get_offset()) {
1570                // Chunk ended correctly
1571                blockLength = maxBlockLength;
1572            } else {
1573                // Skip over anything left by bad unmarshaling code (ex:
1574                // a buggy custom unmarshaler).  See handleEndOfValue.
1575                if (blockLength > get_offset()) {
1576                    skipToOffset(blockLength);
1577                } else {
1578                    throw wrapper.badChunkLength( new Integer( blockLength ),
1579                        new Integer( get_offset() ) ) ;
1580                }
1581            }
1582        }
1583    }
1584
1585    private int readValueTag(){
1586        // outerValueDone = false;
1587        return read_long();
1588    }
1589
1590    public org.omg.CORBA.ORB orb() {
1591        return orb;
1592    }
1593
1594    // ------------ End RMI related methods --------------------------
1595
1596    public final void read_boolean_array(boolean[] value, int offset, int length) {
1597        for(int i=0; i < length; i++) {
1598            value[i+offset] = read_boolean();
1599        }
1600    }
1601
1602    public final void read_char_array(char[] value, int offset, int length) {
1603        for(int i=0; i < length; i++) {
1604            value[i+offset] = read_char();
1605        }
1606    }
1607
1608    public final void read_wchar_array(char[] value, int offset, int length) {
1609        for(int i=0; i < length; i++) {
1610            value[i+offset] = read_wchar();
1611        }
1612    }
1613
1614    public final void read_short_array(short[] value, int offset, int length) {
1615        for(int i=0; i < length; i++) {
1616            value[i+offset] = read_short();
1617        }
1618    }
1619
1620    public final void read_ushort_array(short[] value, int offset, int length) {
1621        read_short_array(value, offset, length);
1622    }
1623
1624    public final void read_long_array(int[] value, int offset, int length) {
1625        for(int i=0; i < length; i++) {
1626            value[i+offset] = read_long();
1627        }
1628    }
1629
1630    public final void read_ulong_array(int[] value, int offset, int length) {
1631        read_long_array(value, offset, length);
1632    }
1633
1634    public final void read_longlong_array(long[] value, int offset, int length) {
1635        for(int i=0; i < length; i++) {
1636            value[i+offset] = read_longlong();
1637        }
1638    }
1639
1640    public final void read_ulonglong_array(long[] value, int offset, int length) {
1641        read_longlong_array(value, offset, length);
1642    }
1643
1644    public final void read_float_array(float[] value, int offset, int length) {
1645        for(int i=0; i < length; i++) {
1646            value[i+offset] = read_float();
1647        }
1648    }
1649
1650    public final void read_double_array(double[] value, int offset, int length) {
1651        for(int i=0; i < length; i++) {
1652            value[i+offset] = read_double();
1653        }
1654    }
1655
1656    public final void read_any_array(org.omg.CORBA.Any[] value, int offset, int length) {
1657        for(int i=0; i < length; i++) {
1658            value[i+offset] = read_any();
1659        }
1660    }
1661
1662    //--------------------------------------------------------------------//
1663    // CDRInputStream state management.
1664    //
1665
1666    /**
1667     * Are we at the end of the input stream?
1668     */
1669//     public final boolean isAtEnd() {
1670//      return bbwi.position() == bbwi.buflen;
1671//     }
1672
1673//     public int available() throws IOException {
1674//         return bbwi.buflen - bbwi.position();
1675//     }
1676
1677    private String read_repositoryIds() {
1678
1679        // Read # of repository ids
1680        int numRepIds = read_long();
1681        if (numRepIds == 0xffffffff) {
1682            int indirection = read_long() + get_offset() - 4;
1683            if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
1684                return (String)repositoryIdCache.getKey(indirection);
1685            else
1686                throw wrapper.unableToLocateRepIdArray( new Integer( indirection ) ) ;
1687        } else {
1688
1689            // read first array element and store it as an indirection to the whole array
1690            int indirection = get_offset();
1691            String repID = read_repositoryId();
1692            if (repositoryIdCache == null)
1693                repositoryIdCache = new CacheTable(orb,false);
1694            repositoryIdCache.put(repID, indirection);
1695
1696            // read and ignore the subsequent array elements, but put them in the
1697            // indirection table in case there are later indirections back to them
1698            for (int i = 1; i < numRepIds; i++) {
1699                read_repositoryId();
1700            }
1701
1702            return repID;
1703        }
1704    }
1705
1706    private final String read_repositoryId()
1707    {
1708        String result = readStringOrIndirection(true);
1709
1710        if (result == null) { // Indirection
1711            int indirection = read_long() + get_offset() - 4;
1712
1713            if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
1714                return (String)repositoryIdCache.getKey(indirection);
1715            else
1716                throw wrapper.badRepIdIndirection( CompletionStatus.COMPLETED_MAYBE,
1717                    new Integer(bbwi.position()) ) ;
1718        } else {
1719            if (repositoryIdCache == null)
1720                repositoryIdCache = new CacheTable(orb,false);
1721            repositoryIdCache.put(result, stringIndirection);
1722        }
1723
1724        return result ;
1725    }
1726
1727    private final String read_codebase_URL()
1728    {
1729        String result = readStringOrIndirection(true);
1730
1731        if (result == null) { // Indirection
1732            int indirection = read_long() + get_offset() - 4;
1733
1734            if (codebaseCache != null && codebaseCache.containsVal(indirection))
1735                return (String)codebaseCache.getKey(indirection);
1736            else
1737                throw wrapper.badCodebaseIndirection(
1738                    CompletionStatus.COMPLETED_MAYBE,
1739                    new Integer(bbwi.position()) ) ;
1740        } else {
1741            if (codebaseCache == null)
1742                codebaseCache = new CacheTable(orb,false);
1743            codebaseCache.put(result, stringIndirection);
1744        }
1745
1746        return result;
1747    }
1748
1749    /* DataInputStream methods */
1750
1751    public java.lang.Object read_Abstract () {
1752        return read_abstract_interface();
1753    }
1754
1755    public java.io.Serializable read_Value () {
1756        return read_value();
1757    }
1758
1759    public void read_any_array (org.omg.CORBA.AnySeqHolder seq, int offset, int length) {
1760        read_any_array(seq.value, offset, length);
1761    }
1762
1763    public void read_boolean_array (org.omg.CORBA.BooleanSeqHolder seq, int offset, int length) {
1764        read_boolean_array(seq.value, offset, length);
1765    }
1766
1767    public void read_char_array (org.omg.CORBA.CharSeqHolder seq, int offset, int length) {
1768        read_char_array(seq.value, offset, length);
1769    }
1770
1771    public void read_wchar_array (org.omg.CORBA.WCharSeqHolder seq, int offset, int length) {
1772        read_wchar_array(seq.value, offset, length);
1773    }
1774
1775    public void read_octet_array (org.omg.CORBA.OctetSeqHolder seq, int offset, int length) {
1776        read_octet_array(seq.value, offset, length);
1777    }
1778
1779    public void read_short_array (org.omg.CORBA.ShortSeqHolder seq, int offset, int length) {
1780        read_short_array(seq.value, offset, length);
1781    }
1782
1783    public void read_ushort_array (org.omg.CORBA.UShortSeqHolder seq, int offset, int length) {
1784        read_ushort_array(seq.value, offset, length);
1785    }
1786
1787    public void read_long_array (org.omg.CORBA.LongSeqHolder seq, int offset, int length) {
1788        read_long_array(seq.value, offset, length);
1789    }
1790
1791    public void read_ulong_array (org.omg.CORBA.ULongSeqHolder seq, int offset, int length) {
1792        read_ulong_array(seq.value, offset, length);
1793    }
1794
1795    public void read_ulonglong_array (org.omg.CORBA.ULongLongSeqHolder seq, int offset, int length) {
1796        read_ulonglong_array(seq.value, offset, length);
1797    }
1798
1799    public void read_longlong_array (org.omg.CORBA.LongLongSeqHolder seq, int offset, int length) {
1800        read_longlong_array(seq.value, offset, length);
1801    }
1802
1803    public void read_float_array (org.omg.CORBA.FloatSeqHolder seq, int offset, int length) {
1804        read_float_array(seq.value, offset, length);
1805    }
1806
1807    public void read_double_array (org.omg.CORBA.DoubleSeqHolder seq, int offset, int length) {
1808        read_double_array(seq.value, offset, length);
1809    }
1810
1811    public java.math.BigDecimal read_fixed(short digits, short scale) {
1812        // digits isn't really needed here
1813        StringBuffer buffer = read_fixed_buffer();
1814        if (digits != buffer.length())
1815            throw wrapper.badFixed( new Integer(digits),
1816                new Integer(buffer.length()) ) ;
1817        buffer.insert(digits - scale, '.');
1818        return new BigDecimal(buffer.toString());
1819    }
1820
1821    // This method is unable to yield the correct scale.
1822    public java.math.BigDecimal read_fixed() {
1823        return new BigDecimal(read_fixed_buffer().toString());
1824    }
1825
1826    // Each octet contains (up to) two decimal digits.
1827    // If the fixed type has an odd number of decimal digits, then the representation
1828    // begins with the first (most significant) digit.
1829    // Otherwise, this first half-octet is all zero, and the first digit
1830    // is in the second half-octet.
1831    // The sign configuration, in the last half-octet of the representation,
1832    // is 0xD for negative numbers and 0xC for positive and zero values.
1833    private StringBuffer read_fixed_buffer() {
1834        StringBuffer buffer = new StringBuffer(64);
1835        byte doubleDigit;
1836        int firstDigit;
1837        int secondDigit;
1838        boolean wroteFirstDigit = false;
1839        boolean more = true;
1840        while (more) {
1841            doubleDigit = this.read_octet();
1842            firstDigit = (int)((doubleDigit & 0xf0) >> 4);
1843            secondDigit = (int)(doubleDigit & 0x0f);
1844            if (wroteFirstDigit || firstDigit != 0) {
1845                buffer.append(Character.forDigit(firstDigit, 10));
1846                wroteFirstDigit = true;
1847            }
1848            if (secondDigit == 12) {
1849                // positive number or zero
1850                if ( ! wroteFirstDigit) {
1851                    // zero
1852                    return new StringBuffer("0.0");
1853                } else {
1854                    // positive number
1855                    // done
1856                }
1857                more = false;
1858            } else if (secondDigit == 13) {
1859                // negative number
1860                buffer.insert(0, '-');
1861                more = false;
1862            } else {
1863                buffer.append(Character.forDigit(secondDigit, 10));
1864                wroteFirstDigit = true;
1865            }
1866        }
1867        return buffer;
1868    }
1869
1870    private final static String _id = "IDL:omg.org/CORBA/DataInputStream:1.0";
1871    private final static String[] _ids = { _id };
1872
1873    public String[] _truncatable_ids() {
1874        if (_ids == null)
1875            return null;
1876
1877        return (String[])_ids.clone();
1878    }
1879
1880    /* for debugging */
1881
1882    public void printBuffer() {
1883        CDRInputStream_1_0.printBuffer(this.bbwi);
1884    }
1885
1886    public static void printBuffer(ByteBufferWithInfo bbwi) {
1887
1888        System.out.println("----- Input Buffer -----");
1889        System.out.println();
1890        System.out.println("Current position: " + bbwi.position());
1891        System.out.println("Total length : " + bbwi.buflen);
1892        System.out.println();
1893
1894        try {
1895
1896            char[] charBuf = new char[16];
1897
1898            for (int i = 0; i < bbwi.buflen; i += 16) {
1899
1900                int j = 0;
1901
1902                // For every 16 bytes, there is one line
1903                // of output.  First, the hex output of
1904                // the 16 bytes with each byte separated
1905                // by a space.
1906                while (j < 16 && j + i < bbwi.buflen) {
1907                    int k = bbwi.byteBuffer.get(i + j);
1908                    if (k < 0)
1909                        k = 256 + k;
1910                    String hex = Integer.toHexString(k);
1911                    if (hex.length() == 1)
1912                        hex = "0" + hex;
1913                    System.out.print(hex + " ");
1914                    j++;
1915                }
1916
1917                // Add any extra spaces to align the
1918                // text column in case we didn't end
1919                // at 16
1920                while (j < 16) {
1921                    System.out.print("   ");
1922                    j++;
1923                }
1924
1925                // Now output the ASCII equivalents.  Non-ASCII
1926                // characters are shown as periods.
1927                int x = 0;
1928                while (x < 16 && x + i < bbwi.buflen) {
1929                    if (ORBUtility.isPrintable((char)bbwi.byteBuffer.get(i + x)))
1930                        charBuf[x] = (char)bbwi.byteBuffer.get(i + x);
1931                    else
1932                        charBuf[x] = '.';
1933                    x++;
1934                }
1935                System.out.println(new String(charBuf, 0, x));
1936            }
1937
1938        } catch (Throwable t) {
1939            t.printStackTrace();
1940        }
1941
1942        System.out.println("------------------------");
1943    }
1944
1945    public ByteBuffer getByteBuffer() {
1946        ByteBuffer result = null;
1947        if (bbwi != null) {
1948            result = bbwi.byteBuffer;
1949        }
1950        return result;
1951    }
1952
1953    public int getBufferLength() {
1954        return bbwi.buflen;
1955    }
1956
1957    public void setBufferLength(int value) {
1958        bbwi.buflen = value;
1959        bbwi.byteBuffer.limit(bbwi.buflen);
1960    }
1961
1962    public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
1963        this.bbwi = bbwi;
1964    }
1965
1966    public void setByteBuffer(ByteBuffer byteBuffer) {
1967        bbwi.byteBuffer = byteBuffer;
1968    }
1969
1970    public int getIndex() {
1971        return bbwi.position();
1972    }
1973
1974    public void setIndex(int value) {
1975        bbwi.position(value);
1976    }
1977
1978    public boolean isLittleEndian() {
1979        return littleEndian;
1980    }
1981
1982    public void orb(org.omg.CORBA.ORB orb) {
1983        this.orb = (ORB)orb;
1984    }
1985
1986    public BufferManagerRead getBufferManager() {
1987        return bufferManagerRead;
1988    }
1989
1990    private void skipToOffset(int offset) {
1991
1992        // Number of bytes to skip
1993        int len = offset - get_offset();
1994
1995        int n = 0;
1996
1997        while (n < len) {
1998            int avail;
1999            int bytes;
2000            int wanted;
2001
2002            avail = bbwi.buflen - bbwi.position();
2003            if (avail <= 0) {
2004                grow(1, 1);
2005                avail = bbwi.buflen - bbwi.position();
2006            }
2007
2008            wanted = len - n;
2009            bytes = (wanted < avail) ? wanted : avail;
2010            bbwi.position(bbwi.position() + bytes);
2011            n += bytes;
2012        }
2013    }
2014
2015
2016    // Mark and reset -------------------------------------------------
2017
2018    protected MarkAndResetHandler markAndResetHandler = null;
2019
2020    protected class StreamMemento
2021    {
2022        // These are the fields that may change after marking
2023        // the stream position, so we need to save them.
2024        private int blockLength_;
2025        private int end_flag_;
2026        private int chunkedValueNestingLevel_;
2027        private int valueIndirection_;
2028        private int stringIndirection_;
2029        private boolean isChunked_;
2030        private javax.rmi.CORBA.ValueHandler valueHandler_;
2031        private ByteBufferWithInfo bbwi_;
2032        private boolean specialNoOptionalDataState_;
2033
2034        public StreamMemento()
2035        {
2036            blockLength_ = blockLength;
2037            end_flag_ = end_flag;
2038            chunkedValueNestingLevel_ = chunkedValueNestingLevel;
2039            valueIndirection_ = valueIndirection;
2040            stringIndirection_ = stringIndirection;
2041            isChunked_ = isChunked;
2042            valueHandler_ = valueHandler;
2043            specialNoOptionalDataState_ = specialNoOptionalDataState;
2044            bbwi_ = new ByteBufferWithInfo(bbwi);
2045        }
2046    }
2047
2048    public java.lang.Object createStreamMemento() {
2049        return new StreamMemento();
2050    }
2051
2052    public void restoreInternalState(java.lang.Object streamMemento) {
2053
2054        StreamMemento mem = (StreamMemento)streamMemento;
2055
2056        blockLength = mem.blockLength_;
2057        end_flag = mem.end_flag_;
2058        chunkedValueNestingLevel = mem.chunkedValueNestingLevel_;
2059        valueIndirection = mem.valueIndirection_;
2060        stringIndirection = mem.stringIndirection_;
2061        isChunked = mem.isChunked_;
2062        valueHandler = mem.valueHandler_;
2063        specialNoOptionalDataState = mem.specialNoOptionalDataState_;
2064        bbwi = mem.bbwi_;
2065    }
2066
2067    public int getPosition() {
2068        return get_offset();
2069    }
2070
2071    public void mark(int readlimit) {
2072        markAndResetHandler.mark(this);
2073    }
2074
2075    public void reset() {
2076        markAndResetHandler.reset();
2077    }
2078
2079    // ---------------------------------- end Mark and Reset
2080
2081    // Provides a hook so subclasses of CDRInputStream can provide
2082    // a CodeBase.  This ultimately allows us to grab a Connection
2083    // instance in IIOPInputStream, the only subclass where this
2084    // is actually used.
2085    CodeBase getCodeBase() {
2086        return parent.getCodeBase();
2087    }
2088
2089    /**
2090     * Attempts to find the class described by the given
2091     * repository ID string and expected type.  The first
2092     * attempt is to find the class locally, falling back
2093     * on the URL that came with the value.  The second
2094     * attempt is to use a URL from the remote CodeBase.
2095     */
2096    private Class getClassFromString(String repositoryIDString,
2097                                     String codebaseURL,
2098                                     Class expectedType)
2099    {
2100        RepositoryIdInterface repositoryID
2101            = repIdStrs.getFromString(repositoryIDString);
2102
2103        try {
2104            try {
2105                // First try to load the class locally, then use
2106                // the provided URL (if it isn't null)
2107                return repositoryID.getClassFromType(expectedType,
2108                                                     codebaseURL);
2109            } catch (ClassNotFoundException cnfeOuter) {
2110
2111                try {
2112
2113                    if (getCodeBase() == null) {
2114                        return null; // class cannot be loaded remotely.
2115                    }
2116
2117                    // Get a URL from the remote CodeBase and retry
2118                    codebaseURL = getCodeBase().implementation(repositoryIDString);
2119
2120                    // Don't bother trying to find it locally again if
2121                    // we got a null URL
2122                    if (codebaseURL == null)
2123                        return null;
2124
2125                    return repositoryID.getClassFromType(expectedType,
2126                                                         codebaseURL);
2127                } catch (ClassNotFoundException cnfeInner) {
2128                    dprintThrowable(cnfeInner);
2129                    // Failed to load the class
2130                    return null;
2131                }
2132            }
2133        } catch (MalformedURLException mue) {
2134            // Always report a bad URL
2135            throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
2136                mue, repositoryIDString, codebaseURL ) ;
2137        }
2138    }
2139
2140    /**
2141     * Attempts to find the class described by the given
2142     * repository ID string.  At most, three attempts are made:
2143     * Try to find it locally, through the provided URL, and
2144     * finally, via a URL from the remote CodeBase.
2145     */
2146    private Class getClassFromString(String repositoryIDString,
2147                                     String codebaseURL)
2148    {
2149        RepositoryIdInterface repositoryID
2150            = repIdStrs.getFromString(repositoryIDString);
2151
2152        for (int i = 0; i < 3; i++) {
2153
2154            try {
2155
2156                switch (i)
2157                {
2158                    case 0:
2159                        // First try to load the class locally
2160                        return repositoryID.getClassFromType();
2161                    case 1:
2162                        // Try to load the class using the provided
2163                        // codebase URL (falls out below)
2164                        break;
2165                    case 2:
2166                        // Try to load the class using a URL from the
2167                        // remote CodeBase
2168                        codebaseURL = getCodeBase().implementation(repositoryIDString);
2169                        break;
2170                }
2171
2172                // Don't bother if the codebaseURL is null
2173                if (codebaseURL == null)
2174                    continue;
2175
2176                return repositoryID.getClassFromType(codebaseURL);
2177
2178            } catch(ClassNotFoundException cnfe) {
2179                // Will ultimately return null if all three
2180                // attempts fail, but don't do anything here.
2181            } catch (MalformedURLException mue) {
2182                throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
2183                    mue, repositoryIDString, codebaseURL ) ;
2184            }
2185        }
2186
2187        // If we get here, we have failed to load the class
2188        dprint("getClassFromString failed with rep id "
2189               + repositoryIDString
2190               + " and codebase "
2191               + codebaseURL);
2192
2193        return null;
2194    }
2195
2196    // Utility method used to get chars from bytes
2197    char[] getConvertedChars(int numBytes,
2198                             CodeSetConversion.BTCConverter converter) {
2199
2200        // REVISIT - Look at CodeSetConversion.BTCConverter to see
2201        //           if it can work with an NIO ByteBuffer. We should
2202        //           avoid getting the bytes into an array if possible.
2203
2204        // To be honest, I doubt this saves much real time
2205        if (bbwi.buflen - bbwi.position() >= numBytes) {
2206            // If the entire string is in this buffer,
2207            // just convert directly from the bbwi rather than
2208            // allocating and copying.
2209            byte[] tmpBuf;
2210            if (bbwi.byteBuffer.hasArray())
2211            {
2212                tmpBuf = bbwi.byteBuffer.array();
2213            }
2214            else
2215            {
2216                 tmpBuf = new byte[bbwi.buflen];
2217                 // Microbenchmarks are showing a loop of ByteBuffer.get(int)
2218                 // being faster than ByteBuffer.get(byte[], int, int).
2219                 for (int i = 0; i < bbwi.buflen; i++)
2220                     tmpBuf[i] = bbwi.byteBuffer.get(i);
2221            }
2222            char[] result = converter.getChars(tmpBuf,bbwi.position(),numBytes);
2223
2224            bbwi.position(bbwi.position() + numBytes);
2225            return result;
2226        } else {
2227            // Stretches across buffers.  Unless we provide an
2228            // incremental conversion interface, allocate and
2229            // copy the bytes.
2230            byte[] bytes = new byte[numBytes];
2231            read_octet_array(bytes, 0, bytes.length);
2232
2233            return converter.getChars(bytes, 0, numBytes);
2234        }
2235    }
2236
2237    protected CodeSetConversion.BTCConverter getCharConverter() {
2238        if (charConverter == null)
2239            charConverter = parent.createCharBTCConverter();
2240
2241        return charConverter;
2242    }
2243
2244    protected CodeSetConversion.BTCConverter getWCharConverter() {
2245        if (wcharConverter == null)
2246            wcharConverter = parent.createWCharBTCConverter();
2247
2248        return wcharConverter;
2249    }
2250
2251    protected void dprintThrowable(Throwable t) {
2252        if (debug && t != null)
2253            t.printStackTrace();
2254    }
2255
2256    protected void dprint(String msg) {
2257        if (debug) {
2258            ORBUtility.dprint(this, msg);
2259        }
2260    }
2261
2262    /**
2263     * Aligns the current position on the given octet boundary
2264     * if there are enough bytes available to do so.  Otherwise,
2265     * it just returns.  This is used for some (but not all)
2266     * GIOP 1.2 message headers.
2267     */
2268
2269    void alignOnBoundary(int octetBoundary) {
2270        int needed = computeAlignment(bbwi.position(), octetBoundary);
2271
2272        if (bbwi.position() + needed <= bbwi.buflen)
2273        {
2274            bbwi.position(bbwi.position() + needed);
2275        }
2276    }
2277
2278    public void resetCodeSetConverters() {
2279        charConverter = null;
2280        wcharConverter = null;
2281    }
2282
2283    public void start_value() {
2284        // Read value tag
2285        int vType = readValueTag();
2286
2287        if (vType == 0) {
2288            // Stream needs to go into a state where it
2289            // throws standard exception until end_value
2290            // is called.  This means the sender didn't
2291            // send any custom data.  If the reader here
2292            // tries to read more, we need to throw an
2293            // exception before reading beyond where
2294            // we're supposed to
2295            specialNoOptionalDataState = true;
2296
2297            return;
2298        }
2299
2300        if (vType == 0xffffffff) {
2301            // One should never indirect to a custom wrapper
2302            throw wrapper.customWrapperIndirection(
2303                CompletionStatus.COMPLETED_MAYBE);
2304        }
2305
2306        if (repIdUtil.isCodeBasePresent(vType)) {
2307            throw wrapper.customWrapperWithCodebase(
2308                CompletionStatus.COMPLETED_MAYBE);
2309        }
2310
2311        if (repIdUtil.getTypeInfo(vType)
2312            != RepositoryIdUtility.SINGLE_REP_TYPE_INFO) {
2313            throw wrapper.customWrapperNotSingleRepid(
2314                CompletionStatus.COMPLETED_MAYBE);
2315        }
2316
2317
2318        // REVISIT - Could verify repository ID even though
2319        // it isn't used elsewhere
2320        read_repositoryId();
2321
2322        // Note: isChunked should be true here.  Should have
2323        // been set to true in the containing value's read_value
2324        // method.
2325
2326        start_block();
2327        end_flag--;
2328        chunkedValueNestingLevel--;
2329    }
2330
2331    public void end_value() {
2332
2333        if (specialNoOptionalDataState) {
2334            specialNoOptionalDataState = false;
2335            return;
2336        }
2337
2338        handleEndOfValue();
2339        readEndTag();
2340
2341        // Note that isChunked should still be true here.
2342        // If the containing valuetype is the highest
2343        // chunked value, it will get set to false
2344        // at the end of read_value.
2345
2346        // allow for possible continuation chunk
2347        start_block();
2348    }
2349
2350    public void close() throws IOException
2351    {
2352
2353        // tell BufferManagerRead to release any ByteBuffers
2354        getBufferManager().close(bbwi);
2355
2356        // It's possible bbwi.byteBuffer is shared between
2357        // this InputStream and an OutputStream. Thus, we check
2358        // if the Input/Output streams are using the same ByteBuffer.
2359        // If they sharing the same ByteBuffer we need to ensure only
2360        // one of those ByteBuffers are released to the ByteBufferPool.
2361
2362        if (bbwi != null && getByteBuffer() != null)
2363        {
2364            MessageMediator messageMediator = parent.getMessageMediator();
2365            if (messageMediator != null)
2366            {
2367                CDROutputObject outputObj =
2368                             (CDROutputObject)messageMediator.getOutputObject();
2369                if (outputObj != null)
2370                {
2371                    if (outputObj.isSharing(getByteBuffer()))
2372                    {
2373                        // Set OutputStream's ByteBuffer and bbwi to null
2374                        // so its ByteBuffer cannot be released to the pool
2375                        outputObj.setByteBuffer(null);
2376                        outputObj.setByteBufferWithInfo(null);
2377                    }
2378                }
2379            }
2380
2381            // release this stream's ByteBuffer to the pool
2382            ByteBufferPool byteBufferPool = orb.getByteBufferPool();
2383            if (debug)
2384            {
2385                // print address of ByteBuffer being released
2386                int bbAddress = System.identityHashCode(bbwi.byteBuffer);
2387                StringBuffer sb = new StringBuffer(80);
2388                sb.append(".close - releasing ByteBuffer id (");
2389                sb.append(bbAddress).append(") to ByteBufferPool.");
2390                String msg = sb.toString();
2391                dprint(msg);
2392            }
2393            byteBufferPool.releaseByteBuffer(bbwi.byteBuffer);
2394            bbwi.byteBuffer = null;
2395            bbwi = null;
2396        }
2397    }
2398}
2399