IIOPInputStream.java revision 716:dc8238c2c66a
1/*
2 * Copyright (c) 1998, 2015, 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 * Licensed Materials - Property of IBM
27 * RMI-IIOP v1.0
28 * Copyright IBM Corp. 1998 1999  All Rights Reserved
29 *
30 */
31
32package com.sun.corba.se.impl.io;
33
34import java.io.InputStream;
35import java.io.IOException;
36import java.io.StreamCorruptedException;
37import java.io.ObjectInputValidation;
38import java.io.NotActiveException;
39import java.io.InvalidObjectException;
40import java.io.InvalidClassException;
41import java.io.DataInputStream;
42import java.io.OptionalDataException;
43import java.io.WriteAbortedException;
44import java.io.Externalizable;
45import java.io.EOFException;
46import java.lang.reflect.*;
47import java.util.Vector;
48import java.util.Stack;
49import java.util.Hashtable;
50import java.util.Enumeration;
51
52import sun.corba.Bridge ;
53
54import java.security.AccessController ;
55import java.security.PrivilegedAction ;
56
57import com.sun.corba.se.impl.io.ObjectStreamClass;
58import com.sun.corba.se.impl.util.Utility;
59
60import org.omg.CORBA.portable.ValueInputStream;
61
62import org.omg.CORBA.ValueMember;
63import org.omg.CORBA.SystemException;
64import org.omg.CORBA.TCKind;
65import org.omg.CORBA.ORB;
66import org.omg.CORBA.CompletionStatus;
67import org.omg.CORBA.portable.IndirectionException;
68import org.omg.CORBA.MARSHAL;
69import org.omg.CORBA.TypeCode;
70
71import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
72import com.sun.org.omg.SendingContext.CodeBase;
73
74import javax.rmi.PortableRemoteObject;
75import javax.rmi.CORBA.Util;
76import javax.rmi.CORBA.ValueHandler;
77
78import java.security.*;
79import java.util.*;
80
81import com.sun.corba.se.impl.orbutil.ObjectUtility ;
82import com.sun.corba.se.impl.logging.OMGSystemException ;
83import com.sun.corba.se.impl.logging.UtilSystemException ;
84
85import com.sun.corba.se.spi.logging.CORBALogDomains ;
86
87/**
88 * IIOPInputStream is used by the ValueHandlerImpl to handle Java serialization
89 * input semantics.
90 *
91 * @author  Stephen Lewallen
92 * @since   JDK1.1.6
93 */
94
95public class IIOPInputStream
96    extends com.sun.corba.se.impl.io.InputStreamHook
97{
98    private static Bridge bridge =
99        (Bridge)AccessController.doPrivileged(
100            new PrivilegedAction() {
101                public Object run() {
102                    return Bridge.get() ;
103                }
104            }
105        ) ;
106
107    private static OMGSystemException omgWrapper = OMGSystemException.get(
108        CORBALogDomains.RPC_ENCODING ) ;
109    private static UtilSystemException utilWrapper = UtilSystemException.get(
110        CORBALogDomains.RPC_ENCODING ) ;
111
112    // Necessary to pass the appropriate fields into the
113    // defaultReadObjectDelegate method (which takes no
114    // parameters since it's called from
115    // java.io.ObjectInpuStream defaultReadObject()
116    // which we can't change).
117    //
118    // This is only used in the case where the fields had
119    // to be obtained remotely because of a serializable
120    // version difference.  Set in inputObjectUsingFVD.
121    // Part of serialization evolution fixes for Ladybird,
122    // bug 4365188.
123    private ValueMember defaultReadObjectFVDMembers[] = null;
124
125    private org.omg.CORBA_2_3.portable.InputStream orbStream;
126
127    private CodeBase cbSender;
128
129    private ValueHandlerImpl vhandler;  //d4365188
130
131    private Object currentObject = null;
132
133    private ObjectStreamClass currentClassDesc = null;
134
135    private Class currentClass = null;
136
137    private int recursionDepth = 0;
138
139    private int simpleReadDepth = 0;
140
141    // The ActiveRecursionManager replaces the old RecursionManager which
142    // used to record how many recursions were made, and resolve them after
143    // an object was completely deserialized.
144    //
145    // That created problems (as in bug 4414154) because when custom
146    // unmarshaling in readObject, there can be recursive references
147    // to one of the objects currently being unmarshaled, and the
148    // passive recursion system failed.
149    ActiveRecursionManager activeRecursionMgr = new ActiveRecursionManager();
150
151    private IOException abortIOException = null;
152
153    /* Remember the first exception that stopped this stream. */
154    private ClassNotFoundException abortClassNotFoundException = null;
155
156    /* Vector of validation callback objects
157     * The vector is created as needed. The vector is maintained in
158     * order of highest (first) priority to lowest
159     */
160    private Vector callbacks;
161
162    // Serialization machinery fields
163    /* Arrays used to keep track of classes and ObjectStreamClasses
164     * as they are being merged; used in inputObject.
165     * spClass is the stack pointer for both.  */
166    ObjectStreamClass[] classdesc;
167    Class[] classes;
168    int spClass;
169
170    private static final String kEmptyStr = "";
171
172    // TCKind TypeCodes used in FVD inputClassFields
173    //public static final TypeCode kRemoteTypeCode = new TypeCodeImpl(TCKind._tk_objref);
174    //public static final TypeCode kValueTypeCode =  new TypeCodeImpl(TCKind._tk_value);
175    // removed TypeCodeImpl dependency
176    public static final TypeCode kRemoteTypeCode = ORB.init().get_primitive_tc(TCKind.tk_objref);
177    public static final TypeCode kValueTypeCode =  ORB.init().get_primitive_tc(TCKind.tk_value);
178
179    // TESTING CODE - useFVDOnly should be made final before FCS in order to
180    // optimize out the check.
181    private static final boolean useFVDOnly = false;
182
183    private byte streamFormatVersion;
184
185    // Since java.io.OptionalDataException's constructors are
186    // package private, but we need to throw it in some special
187    // cases, we try to do it by reflection.
188    private static final Constructor OPT_DATA_EXCEPTION_CTOR;
189
190    private Object[] readObjectArgList = { this } ;
191
192    static {
193        OPT_DATA_EXCEPTION_CTOR = getOptDataExceptionCtor();
194    }
195
196    // Grab the OptionalDataException boolean ctor and make
197    // it accessible.  Note that any exceptions
198    // will be wrapped in ExceptionInInitializerErrors.
199    private static Constructor getOptDataExceptionCtor() {
200
201        try {
202
203            Constructor result =
204
205                (Constructor) AccessController.doPrivileged(
206                                    new PrivilegedExceptionAction() {
207                    public java.lang.Object run()
208                        throws NoSuchMethodException,
209                        SecurityException {
210
211                        Constructor boolCtor
212                            = OptionalDataException.class.getDeclaredConstructor(
213                                                               new Class[] {
214                                Boolean.TYPE });
215
216                        boolCtor.setAccessible(true);
217
218                        return boolCtor;
219                    }});
220
221            if (result == null)
222                // XXX I18N, logging needed.
223                throw new Error("Unable to find OptionalDataException constructor");
224
225            return result;
226
227        } catch (Exception ex) {
228            // XXX I18N, logging needed.
229            throw new ExceptionInInitializerError(ex);
230        }
231    }
232
233    // Create a new OptionalDataException with the EOF marker
234    // set to true.  See handleOptionalDataMarshalException.
235    private OptionalDataException createOptionalDataException() {
236        try {
237            OptionalDataException result
238                = (OptionalDataException)
239                   OPT_DATA_EXCEPTION_CTOR.newInstance(new Object[] {
240                       Boolean.TRUE });
241
242            if (result == null)
243                // XXX I18N, logging needed.
244                throw new Error("Created null OptionalDataException");
245
246            return result;
247
248        } catch (Exception ex) {
249            // XXX I18N, logging needed.
250            throw new Error("Couldn't create OptionalDataException", ex);
251        }
252    }
253
254    // Return the stream format version currently being used
255    // to deserialize an object
256    protected byte getStreamFormatVersion() {
257        return streamFormatVersion;
258    }
259
260    // At the beginning of data sent by a writeObject or
261    // writeExternal method there is a byte telling the
262    // reader the stream format version.
263    private void readFormatVersion() throws IOException {
264
265        streamFormatVersion = orbStream.read_octet();
266
267        if (streamFormatVersion < 1 ||
268            streamFormatVersion > vhandler.getMaximumStreamFormatVersion()) {
269            SystemException sysex = omgWrapper.unsupportedFormatVersion(
270                    CompletionStatus.COMPLETED_MAYBE);
271            // XXX I18N?  Logging for IOException?
272            IOException result = new IOException("Unsupported format version: "
273                                                 + streamFormatVersion);
274            result.initCause( sysex ) ;
275            throw result ;
276        }
277
278        if (streamFormatVersion == 2) {
279            if (!(orbStream instanceof ValueInputStream)) {
280                SystemException sysex = omgWrapper.notAValueinputstream(
281                    CompletionStatus.COMPLETED_MAYBE);
282                // XXX I18N?  Logging for IOException?
283                IOException result = new IOException("Not a ValueInputStream");
284                result.initCause( sysex ) ;
285                throw result;
286            }
287        }
288    }
289
290    public static void setTestFVDFlag(boolean val){
291        //  useFVDOnly = val;
292    }
293
294    /**
295     * Dummy constructor; passes upper stream a dummy stream;
296     **/
297    public IIOPInputStream()
298        throws java.io.IOException {
299        super();
300        resetStream();
301    }
302
303    final void setOrbStream(org.omg.CORBA_2_3.portable.InputStream os) {
304        orbStream = os;
305    }
306
307    final org.omg.CORBA_2_3.portable.InputStream getOrbStream() {
308        return orbStream;
309    }
310
311    //added setSender and getSender
312    public final void setSender(CodeBase cb) {
313        cbSender = cb;
314    }
315
316    public final CodeBase getSender() {
317        return cbSender;
318    }
319
320    // 4365188 this is added to enable backward compatability w/ wrong
321    // rep-ids
322    public final void setValueHandler(ValueHandler vh) {
323        vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
324    }
325
326    public final ValueHandler getValueHandler() {
327        return (javax.rmi.CORBA.ValueHandler) vhandler;
328    }
329
330    final void increaseRecursionDepth(){
331        recursionDepth++;
332    }
333
334    final int decreaseRecursionDepth(){
335        return --recursionDepth;
336    }
337
338    /**
339     * Override the actions of the final method "readObject()"
340     * in ObjectInputStream.
341     * @since     JDK1.1.6
342     *
343     * Read an object from the ObjectInputStream.
344     * The class of the object, the signature of the class, and the values
345     * of the non-transient and non-static fields of the class and all
346     * of its supertypes are read.  Default deserializing for a class can be
347     * overriden using the writeObject and readObject methods.
348     * Objects referenced by this object are read transitively so
349     * that a complete equivalent graph of objects is reconstructed by readObject. <p>
350     *
351     * The root object is completly restored when all of its fields
352     * and the objects it references are completely restored.  At this
353     * point the object validation callbacks are executed in order
354     * based on their registered priorities. The callbacks are
355     * registered by objects (in the readObject special methods)
356     * as they are individually restored.
357     *
358     * Exceptions are thrown for problems with the InputStream and for classes
359     * that should not be deserialized.  All exceptions are fatal to the
360     * InputStream and leave it in an indeterminate state; it is up to the caller
361     * to ignore or recover the stream state.
362     * @exception java.lang.ClassNotFoundException Class of a serialized object
363     *      cannot be found.
364     * @exception InvalidClassException Something is wrong with a class used by
365     *     serialization.
366     * @exception StreamCorruptedException Control information in the
367     *     stream is inconsistent.
368     * @exception OptionalDataException Primitive data was found in the
369     * stream instead of objects.
370     * @exception IOException Any of the usual Input/Output related exceptions.
371     * @since     JDK1.1
372     */
373    public final synchronized Object readObjectDelegate() throws IOException
374    {
375        try {
376
377            readObjectState.readData(this);
378
379            return orbStream.read_abstract_interface();
380        } catch (MARSHAL marshalException) {
381            handleOptionalDataMarshalException(marshalException, true);
382            throw marshalException;
383        } catch(IndirectionException cdrie)
384            {
385                // The CDR stream had never seen the given offset before,
386                // so check the recursion manager (it will throw an
387                // IOException if it doesn't have a reference, either).
388                return activeRecursionMgr.getObject(cdrie.offset);
389            }
390    }
391
392    final synchronized Object simpleReadObject(Class clz,
393                                  String repositoryID,
394                                  com.sun.org.omg.SendingContext.CodeBase sender,
395                                  int offset)
396                                         /* throws OptionalDataException, ClassNotFoundException, IOException */
397    {
398
399        /* Save the current state and get ready to read an object. */
400        Object prevObject = currentObject;
401        ObjectStreamClass prevClassDesc = currentClassDesc;
402        Class prevClass = currentClass;
403        byte oldStreamFormatVersion = streamFormatVersion;
404
405        simpleReadDepth++;      // Entering
406        Object obj = null;
407
408        /*
409         * Check for reset, handle it before reading an object.
410         */
411        try {
412            // d4365188: backward compatability
413            if (vhandler.useFullValueDescription(clz, repositoryID)) {
414                obj = inputObjectUsingFVD(clz, repositoryID, sender, offset);
415            } else {
416                obj = inputObject(clz, repositoryID, sender, offset);
417            }
418
419            obj = currentClassDesc.readResolve(obj);
420        }
421        catch(ClassNotFoundException cnfe)
422            {
423                bridge.throwException( cnfe ) ;
424                return null;
425            }
426        catch(IOException ioe)
427            {
428                // System.out.println("CLZ = " + clz + "; " + ioe.toString());
429                bridge.throwException(ioe) ;
430                return null;
431            }
432        finally {
433            simpleReadDepth --;
434            currentObject = prevObject;
435            currentClassDesc = prevClassDesc;
436            currentClass = prevClass;
437            streamFormatVersion = oldStreamFormatVersion;
438        }
439
440
441        /* Check for thrown exceptions and re-throw them, clearing them if
442         * this is the last recursive call .
443         */
444        IOException exIOE = abortIOException;
445        if (simpleReadDepth == 0)
446            abortIOException = null;
447        if (exIOE != null){
448            bridge.throwException( exIOE ) ;
449            return null;
450        }
451
452
453        ClassNotFoundException exCNF = abortClassNotFoundException;
454        if (simpleReadDepth == 0)
455            abortClassNotFoundException = null;
456        if (exCNF != null) {
457            bridge.throwException( exCNF ) ;
458            return null;
459        }
460
461        return obj;
462    }
463
464    public final synchronized  void simpleSkipObject(String repositoryID,
465                                       com.sun.org.omg.SendingContext.CodeBase sender)
466                                       /* throws OptionalDataException, ClassNotFoundException, IOException */
467    {
468
469        /* Save the current state and get ready to read an object. */
470        Object prevObject = currentObject;
471        ObjectStreamClass prevClassDesc = currentClassDesc;
472        Class prevClass = currentClass;
473        byte oldStreamFormatVersion = streamFormatVersion;
474
475        simpleReadDepth++;      // Entering
476        Object obj = null;
477
478        /*
479         * Check for reset, handle it before reading an object.
480         */
481        try {
482            skipObjectUsingFVD(repositoryID, sender);
483        }
484        catch(ClassNotFoundException cnfe)
485            {
486                bridge.throwException( cnfe ) ;
487                return;
488            }
489        catch(IOException ioe)
490            {
491                bridge.throwException( ioe ) ;
492                return;
493            }
494        finally {
495            simpleReadDepth --;
496            streamFormatVersion = oldStreamFormatVersion;
497            currentObject = prevObject;
498            currentClassDesc = prevClassDesc;
499            currentClass = prevClass;
500        }
501
502
503        /* Check for thrown exceptions and re-throw them, clearing them if
504         * this is the last recursive call .
505         */
506        IOException exIOE = abortIOException;
507        if (simpleReadDepth == 0)
508            abortIOException = null;
509        if (exIOE != null){
510            bridge.throwException( exIOE ) ;
511            return;
512        }
513
514
515        ClassNotFoundException exCNF = abortClassNotFoundException;
516        if (simpleReadDepth == 0)
517            abortClassNotFoundException = null;
518        if (exCNF != null) {
519            bridge.throwException( exCNF ) ;
520            return;
521        }
522
523        return;
524    }
525    /////////////////
526
527    /**
528     * This method is called by trusted subclasses of ObjectOutputStream
529     * that constructed ObjectOutputStream using the
530     * protected no-arg constructor. The subclass is expected to provide
531     * an override method with the modifier "final".
532     *
533     * @return the Object read from the stream.
534     *
535     * @see #ObjectInputStream()
536     * @see #readObject
537     * @since JDK 1.2
538     */
539    protected final Object readObjectOverride()
540        throws OptionalDataException, ClassNotFoundException, IOException
541    {
542        return readObjectDelegate();
543    }
544
545    /**
546     * Override the actions of the final method "defaultReadObject()"
547     * in ObjectInputStream.
548     * @since     JDK1.1.6
549     *
550     * Read the non-static and non-transient fields of the current class
551     * from this stream.  This may only be called from the readObject method
552     * of the class being deserialized. It will throw the NotActiveException
553     * if it is called otherwise.
554     *
555     * @exception java.lang.ClassNotFoundException if the class of a serialized
556     *              object could not be found.
557     * @exception IOException        if an I/O error occurs.
558     * @exception NotActiveException if the stream is not currently reading
559     *              objects.
560     * @since     JDK1.1
561     */
562    final synchronized void defaultReadObjectDelegate()
563    /* throws IOException, ClassNotFoundException, NotActiveException */
564    {
565        try {
566            if (currentObject == null || currentClassDesc == null)
567                // XXX I18N, logging needed.
568                throw new NotActiveException("defaultReadObjectDelegate");
569
570            if (!currentClassDesc.forClass().isAssignableFrom(
571                    currentObject.getClass())) {
572                throw new IOException("Object Type mismatch");
573            }
574
575            // The array will be null unless fields were retrieved
576            // remotely because of a serializable version difference.
577            // Bug fix for 4365188.  See the definition of
578            // defaultReadObjectFVDMembers for more information.
579            if (defaultReadObjectFVDMembers != null &&
580                defaultReadObjectFVDMembers.length > 0) {
581
582                // WARNING:  Be very careful!  What if some of
583                // these fields actually have to do this, too?
584                // This works because the defaultReadObjectFVDMembers
585                // reference is passed to inputClassFields, but
586                // there is no guarantee that
587                // defaultReadObjectFVDMembers will point to the
588                // same array after calling inputClassFields.
589
590                // Use the remote fields to unmarshal.
591                inputClassFields(currentObject,
592                                 currentClass,
593                                 currentClassDesc,
594                                 defaultReadObjectFVDMembers,
595                                 cbSender);
596
597            } else {
598
599                // Use the local fields to unmarshal.
600                ObjectStreamField[] fields =
601                    currentClassDesc.getFieldsNoCopy();
602                if (fields.length > 0) {
603                    inputClassFields(currentObject, currentClass, fields, cbSender);
604                }
605            }
606        }
607        catch(NotActiveException nae)
608            {
609                bridge.throwException( nae ) ;
610            }
611        catch(IOException ioe)
612            {
613                bridge.throwException( ioe ) ;
614            }
615        catch(ClassNotFoundException cnfe)
616            {
617                bridge.throwException( cnfe ) ;
618            }
619
620    }
621
622    /**
623     * Override the actions of the final method "enableResolveObject()"
624     * in ObjectInputStream.
625     * @since     JDK1.1.6
626     *
627     * Enable the stream to allow objects read from the stream to be replaced.
628     * If the stream is a trusted class it is allowed to enable replacment.
629     * Trusted classes are those classes with a classLoader equals null. <p>
630     *
631     * When enabled the resolveObject method is called for every object
632     * being deserialized.
633     *
634     * @exception SecurityException The classloader of this stream object is non-null.
635     * @since     JDK1.1
636     */
637    public final boolean enableResolveObjectDelegate(boolean enable)
638    /* throws SecurityException */
639    {
640        return false;
641    }
642
643    // The following three methods allow the implementing orbStream
644    // to provide mark/reset behavior as defined in java.io.InputStream.
645
646    public final void mark(int readAheadLimit) {
647        orbStream.mark(readAheadLimit);
648    }
649
650    public final boolean markSupported() {
651        return orbStream.markSupported();
652    }
653
654    public final void reset() throws IOException {
655        try {
656            orbStream.reset();
657        } catch (Error e) {
658            IOException err = new IOException(e.getMessage());
659            err.initCause(e) ;
660            throw err ;
661        }
662    }
663
664    public final int available() throws IOException{
665        return 0; // unreliable
666    }
667
668    public final void close() throws IOException{
669        // no op
670    }
671
672    public final int read() throws IOException{
673        try{
674            readObjectState.readData(this);
675
676            return (orbStream.read_octet() << 0) & 0x000000FF;
677        } catch (MARSHAL marshalException) {
678            if (marshalException.minor
679                == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
680                setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
681                return -1;
682            }
683
684            throw marshalException;
685        } catch(Error e) {
686            IOException exc = new IOException(e.getMessage());
687            exc.initCause(e) ;
688            throw exc ;
689        }
690    }
691
692    public final int read(byte data[], int offset, int length) throws IOException{
693        try{
694            readObjectState.readData(this);
695
696            orbStream.read_octet_array(data, offset, length);
697            return length;
698        } catch (MARSHAL marshalException) {
699            if (marshalException.minor
700                == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
701                setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
702                return -1;
703            }
704
705            throw marshalException;
706        } catch(Error e) {
707            IOException exc = new IOException(e.getMessage());
708            exc.initCause(e) ;
709            throw exc ;
710        }
711
712    }
713
714    public final boolean readBoolean() throws IOException{
715        try{
716            readObjectState.readData(this);
717
718            return orbStream.read_boolean();
719        } catch (MARSHAL marshalException) {
720            handleOptionalDataMarshalException(marshalException, false);
721            throw marshalException;
722
723        } catch(Error e) {
724            IOException exc = new IOException(e.getMessage());
725            exc.initCause(e);
726            throw exc ;
727        }
728    }
729
730    public final byte readByte() throws IOException{
731        try{
732            readObjectState.readData(this);
733
734            return orbStream.read_octet();
735        } catch (MARSHAL marshalException) {
736            handleOptionalDataMarshalException(marshalException, false);
737            throw marshalException;
738
739        } catch(Error e) {
740            IOException exc = new IOException(e.getMessage());
741            exc.initCause(e);
742            throw exc ;
743        }
744    }
745
746    public final char readChar() throws IOException{
747        try{
748            readObjectState.readData(this);
749
750            return orbStream.read_wchar();
751        } catch (MARSHAL marshalException) {
752            handleOptionalDataMarshalException(marshalException, false);
753            throw marshalException;
754
755        } catch(Error e) {
756            IOException exc = new IOException(e.getMessage());
757            exc.initCause(e);
758            throw exc ;
759        }
760    }
761
762    public final double readDouble() throws IOException{
763        try{
764            readObjectState.readData(this);
765
766            return orbStream.read_double();
767        } catch (MARSHAL marshalException) {
768            handleOptionalDataMarshalException(marshalException, false);
769            throw marshalException;
770        } catch(Error e) {
771            IOException exc = new IOException(e.getMessage());
772            exc.initCause(e);
773            throw exc ;
774        }
775    }
776
777    public final float readFloat() throws IOException{
778        try{
779            readObjectState.readData(this);
780
781            return orbStream.read_float();
782        } catch (MARSHAL marshalException) {
783            handleOptionalDataMarshalException(marshalException, false);
784            throw marshalException;
785        } catch(Error e) {
786            IOException exc = new IOException(e.getMessage());
787            exc.initCause(e);
788            throw exc ;
789        }
790    }
791
792    public final void readFully(byte data[]) throws IOException{
793// d11623 : implement readFully, required for serializing some core classes
794
795        readFully(data, 0, data.length);
796    }
797
798    public final void readFully(byte data[],  int offset,  int size) throws IOException{
799// d11623 : implement readFully, required for serializing some core classes
800        try{
801            readObjectState.readData(this);
802
803            orbStream.read_octet_array(data, offset, size);
804        } catch (MARSHAL marshalException) {
805            handleOptionalDataMarshalException(marshalException, false);
806
807            throw marshalException;
808        } catch(Error e) {
809            IOException exc = new IOException(e.getMessage());
810            exc.initCause(e);
811            throw exc ;
812        }
813    }
814
815    public final int readInt() throws IOException{
816        try{
817            readObjectState.readData(this);
818
819            return orbStream.read_long();
820        } catch (MARSHAL marshalException) {
821            handleOptionalDataMarshalException(marshalException, false);
822            throw marshalException;
823        } catch(Error e) {
824            IOException exc = new IOException(e.getMessage());
825            exc.initCause(e);
826            throw exc ;
827        }
828    }
829
830    public final String readLine() throws IOException{
831        // XXX I18N, logging needed.
832        throw new IOException("Method readLine not supported");
833    }
834
835    public final long readLong() throws IOException{
836        try{
837            readObjectState.readData(this);
838
839            return orbStream.read_longlong();
840        } catch (MARSHAL marshalException) {
841            handleOptionalDataMarshalException(marshalException, false);
842            throw marshalException;
843        } catch(Error e) {
844            IOException exc = new IOException(e.getMessage());
845            exc.initCause(e);
846            throw exc ;
847        }
848    }
849
850    public final short readShort() throws IOException{
851        try{
852            readObjectState.readData(this);
853
854            return orbStream.read_short();
855        } catch (MARSHAL marshalException) {
856            handleOptionalDataMarshalException(marshalException, false);
857            throw marshalException;
858        } catch(Error e) {
859            IOException exc = new IOException(e.getMessage());
860            exc.initCause(e);
861            throw exc ;
862        }
863    }
864
865    protected final void readStreamHeader() throws IOException, StreamCorruptedException{
866        // no op
867    }
868
869    public final int readUnsignedByte() throws IOException{
870        try{
871            readObjectState.readData(this);
872
873            return (orbStream.read_octet() << 0) & 0x000000FF;
874        } catch (MARSHAL marshalException) {
875            handleOptionalDataMarshalException(marshalException, false);
876            throw marshalException;
877        } catch(Error e) {
878            IOException exc = new IOException(e.getMessage());
879            exc.initCause(e);
880            throw exc ;
881        }
882    }
883
884    public final int readUnsignedShort() throws IOException{
885        try{
886            readObjectState.readData(this);
887
888            return (orbStream.read_ushort() << 0) & 0x0000FFFF;
889        } catch (MARSHAL marshalException) {
890            handleOptionalDataMarshalException(marshalException, false);
891            throw marshalException;
892        } catch(Error e) {
893            IOException exc = new IOException(e.getMessage());
894            exc.initCause(e);
895            throw exc ;
896        }
897    }
898
899    /**
900     * Helper method for correcting the Kestrel bug 4367783 (dealing
901     * with larger than 8-bit chars).  The old behavior is preserved
902     * in orbutil.IIOPInputStream_1_3 in order to interoperate with
903     * our legacy ORBs.
904     */
905    protected String internalReadUTF(org.omg.CORBA.portable.InputStream stream)
906    {
907        return stream.read_wstring();
908    }
909
910    public final String readUTF() throws IOException{
911        try{
912            readObjectState.readData(this);
913
914            return internalReadUTF(orbStream);
915        } catch (MARSHAL marshalException) {
916            handleOptionalDataMarshalException(marshalException, false);
917            throw marshalException;
918        } catch(Error e) {
919            IOException exc = new IOException(e.getMessage());
920            exc.initCause(e);
921            throw exc ;
922        }
923    }
924
925    // If the ORB stream detects an incompatibility between what's
926    // on the wire and what our Serializable's readObject wants,
927    // it throws a MARSHAL exception with a specific minor code.
928    // This is rethrown to the readObject as an OptionalDataException.
929    // So far in RMI-IIOP, this process isn't specific enough to
930    // tell the readObject how much data is available, so we always
931    // set the OptionalDataException's EOF marker to true.
932    private void handleOptionalDataMarshalException(MARSHAL marshalException,
933                                                    boolean objectRead)
934        throws IOException {
935
936        // Java Object Serialization spec 3.4: "If the readObject method
937        // of the class attempts to read more data than is present in the
938        // optional part of the stream for this class, the stream will
939        // return -1 for bytewise reads, throw an EOFException for
940        // primitive data reads, or throw an OptionalDataException
941        // with the eof field set to true for object reads."
942        if (marshalException.minor
943            == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
944
945            IOException result;
946
947            if (!objectRead)
948                result = new EOFException("No more optional data");
949            else
950                result = createOptionalDataException();
951
952            result.initCause(marshalException);
953
954            setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
955
956            throw result;
957        }
958    }
959
960    public final synchronized void registerValidation(ObjectInputValidation obj,
961                                                      int prio)
962        throws NotActiveException, InvalidObjectException{
963        // XXX I18N, logging needed.
964        throw new Error("Method registerValidation not supported");
965    }
966
967    protected final Class resolveClass(ObjectStreamClass v)
968        throws IOException, ClassNotFoundException{
969        // XXX I18N, logging needed.
970        throw new IOException("Method resolveClass not supported");
971    }
972
973    protected final Object resolveObject(Object obj) throws IOException{
974        // XXX I18N, logging needed.
975        throw new IOException("Method resolveObject not supported");
976    }
977
978    public final int skipBytes(int len) throws IOException{
979        try{
980            readObjectState.readData(this);
981
982            byte buf[] = new byte[len];
983            orbStream.read_octet_array(buf, 0, len);
984            return len;
985        } catch (MARSHAL marshalException) {
986            handleOptionalDataMarshalException(marshalException, false);
987
988            throw marshalException;
989        } catch(Error e) {
990            IOException exc = new IOException(e.getMessage());
991            exc.initCause(e) ;
992            throw exc ;
993        }
994    }
995
996    private synchronized Object inputObject(Class clz,
997                               String repositoryID,
998                               com.sun.org.omg.SendingContext.CodeBase sender,
999                               int offset)
1000        throws IOException, ClassNotFoundException
1001    {
1002
1003        /*
1004         * Get the descriptor and then class of the incoming object.
1005         */
1006
1007        currentClassDesc = ObjectStreamClass.lookup(clz);
1008        currentClass = currentClassDesc.forClass();
1009        //currentClassDesc.setClass(currentClass);
1010        if (currentClass == null)
1011            // XXX I18N, logging needed.
1012            throw new ClassNotFoundException(currentClassDesc.getName());
1013
1014        try {
1015            /* If Externalizable,
1016             *  Create an instance and tell it to read its data.
1017             * else,
1018             *  Handle it as a serializable class.
1019             */
1020            if (Enum.class.isAssignableFrom( clz )) {
1021                int ordinal = orbStream.read_long() ;
1022                String value = (String)orbStream.read_value( String.class ) ;
1023                return Enum.valueOf( clz, value ) ;
1024            } else if (currentClassDesc.isExternalizable()) {
1025                try {
1026                    currentObject = (currentClass == null) ?
1027                        null : currentClassDesc.newInstance();
1028                    if (currentObject != null) {
1029
1030                        // Store this object and its beginning position
1031                        // since there might be indirections to it while
1032                        // it's been unmarshalled.
1033                        activeRecursionMgr.addObject(offset, currentObject);
1034
1035                        // Read format version
1036                        readFormatVersion();
1037
1038                        Externalizable ext = (Externalizable)currentObject;
1039                        ext.readExternal(this);
1040                }
1041            } catch (InvocationTargetException e) {
1042                InvalidClassException exc = new InvalidClassException(
1043                    currentClass.getName(),
1044                    "InvocationTargetException accessing no-arg constructor");
1045                exc.initCause( e ) ;
1046                throw exc ;
1047            } catch (UnsupportedOperationException e) {
1048                InvalidClassException exc = new InvalidClassException(
1049                    currentClass.getName(),
1050                    "UnsupportedOperationException accessing no-arg constructor");
1051                exc.initCause( e ) ;
1052                throw exc ;
1053            } catch (InstantiationException e) {
1054                InvalidClassException exc = new InvalidClassException(
1055                    currentClass.getName(),
1056                    "InstantiationException accessing no-arg constructor");
1057                exc.initCause( e ) ;
1058                throw exc ;
1059            }
1060        } // end : if (currentClassDesc.isExternalizable())
1061        else {
1062            /* Count number of classes and descriptors we might have
1063             * to work on.
1064             */
1065
1066            ObjectStreamClass currdesc = currentClassDesc;
1067            Class currclass = currentClass;
1068
1069            int spBase = spClass;       // current top of stack
1070
1071            /* The object's classes should be processed from supertype to subtype
1072             * Push all the clases of the current object onto a stack.
1073             * Note that only the serializable classes are represented
1074             * in the descriptor list.
1075             *
1076             * Handle versioning where one or more supertypes of
1077             * have been inserted or removed.  The stack will
1078             * contain pairs of descriptors and the corresponding
1079             * class.  If the object has a class that did not occur in
1080             * the original the descriptor will be null.  If the
1081             * original object had a descriptor for a class not
1082             * present in the local hierarchy of the object the class will be
1083             * null.
1084             *
1085             */
1086
1087            /*
1088             * This is your basic diff pattern, made simpler
1089             * because reordering is not allowed.
1090             */
1091            // sun.4296963 ibm.11861
1092            // d11861 we should stop when we find the highest serializable class
1093            // We need this so that when we allocate the new object below, we
1094            // can call the constructor of the non-serializable superclass.
1095            // Note that in the JRMP variant of this code the
1096            // ObjectStreamClass.lookup() method handles this, but we've put
1097            // this fix here rather than change lookup because the new behaviour
1098            // is needed in other cases.
1099
1100            for (currdesc = currentClassDesc, currclass = currentClass;
1101                 currdesc != null && currdesc.isSerializable();   /*sun.4296963 ibm.11861*/
1102                 currdesc = currdesc.getSuperclass()) {
1103
1104                /*
1105                 * Search the classes to see if the class of this
1106                 * descriptor appears further up the hierarchy. Until
1107                 * it's found assume its an inserted class.  If it's
1108                 * not found, its the descriptor's class that has been
1109                 * removed.
1110                 */
1111                Class cc = currdesc.forClass();
1112                Class cl;
1113                for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
1114                    if (cc == cl) {
1115                        // found a superclass that matches this descriptor
1116                        break;
1117                    } else {
1118                        /* Ignore a class that doesn't match.  No
1119                         * action is needed since it is already
1120                         * initialized.
1121                         */
1122                    }
1123                } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass())
1124                /* Test if there is room for this new entry.
1125                 * If not, double the size of the arrays and copy the contents.
1126                 */
1127                spClass++;
1128                if (spClass >= classes.length) {
1129                    int newlen = classes.length * 2;
1130                    Class[] newclasses = new Class[newlen];
1131                    ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
1132
1133                    System.arraycopy(classes, 0,
1134                                     newclasses, 0,
1135                                     classes.length);
1136                    System.arraycopy(classdesc, 0,
1137                                     newclassdesc, 0,
1138                                     classes.length);
1139
1140                    classes = newclasses;
1141                    classdesc = newclassdesc;
1142                }
1143
1144                if (cl == null) {
1145                    /* Class not found corresponding to this descriptor.
1146                     * Pop off all the extra classes pushed.
1147                     * Push the descriptor and a null class.
1148                     */
1149                    classdesc[spClass] = currdesc;
1150                    classes[spClass] = null;
1151                } else {
1152                    /* Current class descriptor matches current class.
1153                     * Some classes may have been inserted.
1154                     * Record the match and advance the class, continue
1155                     * with the next descriptor.
1156                     */
1157                    classdesc[spClass] = currdesc;
1158                    classes[spClass] = cl;
1159                    currclass = cl.getSuperclass();
1160                }
1161            } // end : for (currdesc = currentClassDesc, currclass = currentClass;
1162
1163            /* Allocate a new object.  The object is only constructed
1164             * above the highest serializable class and is set to
1165             * default values for all more specialized classes.
1166             */
1167            try {
1168                currentObject = (currentClass == null) ?
1169                    null : currentClassDesc.newInstance() ;
1170
1171                // Store this object and its beginning position
1172                // since there might be indirections to it while
1173                // it's been unmarshalled.
1174                activeRecursionMgr.addObject(offset, currentObject);
1175            } catch (InvocationTargetException e) {
1176                InvalidClassException exc = new InvalidClassException(
1177                    currentClass.getName(),
1178                    "InvocationTargetException accessing no-arg constructor");
1179                exc.initCause( e ) ;
1180                throw exc ;
1181            } catch (UnsupportedOperationException e) {
1182                InvalidClassException exc = new InvalidClassException(
1183                    currentClass.getName(),
1184                    "UnsupportedOperationException accessing no-arg constructor");
1185                exc.initCause( e ) ;
1186                throw exc ;
1187            } catch (InstantiationException e) {
1188                InvalidClassException exc = new InvalidClassException(
1189                    currentClass.getName(),
1190                    "InstantiationException accessing no-arg constructor");
1191                exc.initCause( e ) ;
1192                throw exc ;
1193            }
1194
1195            /*
1196             * For all the pushed descriptors and classes.
1197             *  if the class has its own writeObject and readObject methods
1198             *      call the readObject method
1199             *  else
1200             *      invoke the defaultReadObject method
1201             */
1202            try {
1203                for (spClass = spClass; spClass > spBase; spClass--) {
1204                    /*
1205                     * Set current descriptor and corresponding class
1206                     */
1207                    currentClassDesc = classdesc[spClass];
1208                    currentClass = classes[spClass];
1209                    if (classes[spClass] != null) {
1210                        /* Read the data from the stream described by the
1211                         * descriptor and store into the matching class.
1212                         */
1213
1214                        ReadObjectState oldState = readObjectState;
1215                        setState(DEFAULT_STATE);
1216
1217                        try {
1218
1219                            // Changed since invokeObjectReader no longer does this.
1220                            if (currentClassDesc.hasWriteObject()) {
1221
1222                                // Read format version
1223                                readFormatVersion();
1224
1225                                // Read defaultWriteObject indicator
1226                                boolean calledDefaultWriteObject = readBoolean();
1227
1228                                readObjectState.beginUnmarshalCustomValue(this,
1229                                                                          calledDefaultWriteObject,
1230                                                                          (currentClassDesc.readObjectMethod
1231                                                                           != null));
1232                            } else {
1233                                if (currentClassDesc.hasReadObject())
1234                                    setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED);
1235                            }
1236
1237                            if (!invokeObjectReader(currentClassDesc, currentObject, currentClass) ||
1238                                readObjectState == IN_READ_OBJECT_DEFAULTS_SENT) {
1239
1240                                // Error case of no readObject and didn't call
1241                                // defaultWriteObject handled in default state
1242
1243                                ObjectStreamField[] fields =
1244                                    currentClassDesc.getFieldsNoCopy();
1245                                if (fields.length > 0) {
1246                                    inputClassFields(currentObject, currentClass, fields, sender);
1247                                }
1248                            }
1249
1250                            if (currentClassDesc.hasWriteObject())
1251                                readObjectState.endUnmarshalCustomValue(this);
1252
1253                        } finally {
1254                            setState(oldState);
1255                        }
1256
1257                    } else {
1258
1259                        // _REVISIT_ : Can we ever get here?
1260                        /* No local class for this descriptor,
1261                         * Skip over the data for this class.
1262                         * like defaultReadObject with a null currentObject.
1263                         * The code will read the values but discard them.
1264                         */
1265                            ObjectStreamField[] fields =
1266                                currentClassDesc.getFieldsNoCopy();
1267                            if (fields.length > 0) {
1268                                inputClassFields(null, currentClass, fields, sender);
1269                            }
1270
1271                        }
1272
1273                }
1274            } finally {
1275                                // Make sure we exit at the same stack level as when we started.
1276                spClass = spBase;
1277            }
1278        }
1279        } finally {
1280            // We've completed deserializing this object.  Any
1281            // future indirections will be handled correctly at the
1282            // CDR level.  The ActiveRecursionManager only deals with
1283            // objects currently being deserialized.
1284            activeRecursionMgr.removeObject(offset);
1285        }
1286
1287        return currentObject;
1288    }
1289
1290    // This retrieves a vector of FVD's for the hierarchy of serializable classes stemming from
1291    // repositoryID.  It is assumed that the sender will not provide base_value id's for non-serializable
1292    // classes!
1293    private Vector getOrderedDescriptions(String repositoryID,
1294                                          com.sun.org.omg.SendingContext.CodeBase sender) {
1295        Vector descs = new Vector();
1296
1297        if (sender == null) {
1298            return descs;
1299        }
1300
1301        FullValueDescription aFVD = sender.meta(repositoryID);
1302        while (aFVD != null) {
1303            descs.insertElementAt(aFVD, 0);
1304            if ((aFVD.base_value != null) && !kEmptyStr.equals(aFVD.base_value)) {
1305                aFVD = sender.meta(aFVD.base_value);
1306            }
1307            else return descs;
1308        }
1309
1310        return descs;
1311    }
1312
1313    /**
1314     * This input method uses FullValueDescriptions retrieved from the sender's runtime to
1315     * read in the data.  This method is capable of throwing out data not applicable to client's fields.
1316     * This method handles instances where the reader has a class not sent by the sender, the sender sent
1317     * a class not present on the reader, and/or the reader's class does not match the sender's class.
1318     *
1319     * NOTE : If the local description indicates custom marshaling and the remote type's FVD also
1320     * indicates custom marsahling than the local type is used to read the data off the wire.  However,
1321     * if either says custom while the other does not, a MARSHAL error is thrown.  Externalizable is
1322     * a form of custom marshaling.
1323     *
1324     */
1325    private synchronized Object inputObjectUsingFVD(Class clz,
1326                                       String repositoryID,
1327                                       com.sun.org.omg.SendingContext.CodeBase sender,
1328                                       int offset)
1329        throws IOException, ClassNotFoundException
1330    {
1331        int spBase = spClass;   // current top of stack
1332        try{
1333
1334            /*
1335             * Get the descriptor and then class of the incoming object.
1336             */
1337
1338            ObjectStreamClass currdesc = currentClassDesc = ObjectStreamClass.lookup(clz);
1339            Class currclass = currentClass = clz;
1340
1341            /* If Externalizable,
1342             *  Create an instance and tell it to read its data.
1343             * else,
1344             *  Handle it as a serializable class.
1345             */
1346            if (currentClassDesc.isExternalizable()) {
1347                try {
1348                    currentObject = (currentClass == null) ?
1349                        null : currentClassDesc.newInstance();
1350                    if (currentObject != null) {
1351                        // Store this object and its beginning position
1352                        // since there might be indirections to it while
1353                        // it's been unmarshalled.
1354                        activeRecursionMgr.addObject(offset, currentObject);
1355
1356                        // Read format version
1357                        readFormatVersion();
1358
1359                        Externalizable ext = (Externalizable)currentObject;
1360                        ext.readExternal(this);
1361                    }
1362                } catch (InvocationTargetException e) {
1363                    InvalidClassException exc = new InvalidClassException(
1364                        currentClass.getName(),
1365                        "InvocationTargetException accessing no-arg constructor");
1366                    exc.initCause( e ) ;
1367                    throw exc ;
1368                } catch (UnsupportedOperationException e) {
1369                    InvalidClassException exc = new InvalidClassException(
1370                        currentClass.getName(),
1371                        "UnsupportedOperationException accessing no-arg constructor");
1372                    exc.initCause( e ) ;
1373                    throw exc ;
1374                } catch (InstantiationException e) {
1375                    InvalidClassException exc = new InvalidClassException(
1376                        currentClass.getName(),
1377                        "InstantiationException accessing no-arg constructor");
1378                    exc.initCause( e ) ;
1379                    throw exc ;
1380                }
1381            } else {
1382                /*
1383                 * This is your basic diff pattern, made simpler
1384                 * because reordering is not allowed.
1385                 */
1386                for (currdesc = currentClassDesc, currclass = currentClass;
1387                     currdesc != null && currdesc.isSerializable();   /*sun.4296963 ibm.11861*/
1388
1389                     currdesc = currdesc.getSuperclass()) {
1390
1391                    /*
1392                     * Search the classes to see if the class of this
1393                     * descriptor appears further up the hierarchy. Until
1394                     * it's found assume its an inserted class.  If it's
1395                     * not found, its the descriptor's class that has been
1396                     * removed.
1397                     */
1398                    Class cc = currdesc.forClass();
1399                    Class cl;
1400                    for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
1401                        if (cc == cl) {
1402                            // found a superclass that matches this descriptor
1403                            break;
1404                        } else {
1405                            /* Ignore a class that doesn't match.  No
1406                             * action is needed since it is already
1407                             * initialized.
1408                             */
1409                        }
1410                    } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass())
1411                    /* Test if there is room for this new entry.
1412                     * If not, double the size of the arrays and copy the contents.
1413                     */
1414                    spClass++;
1415                    if (spClass >= classes.length) {
1416                        int newlen = classes.length * 2;
1417                        Class[] newclasses = new Class[newlen];
1418                        ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
1419
1420                        System.arraycopy(classes, 0,
1421                                         newclasses, 0,
1422                                         classes.length);
1423                        System.arraycopy(classdesc, 0,
1424                                         newclassdesc, 0,
1425                                         classes.length);
1426
1427                        classes = newclasses;
1428                        classdesc = newclassdesc;
1429                    }
1430
1431                    if (cl == null) {
1432                        /* Class not found corresponding to this descriptor.
1433                         * Pop off all the extra classes pushed.
1434                         * Push the descriptor and a null class.
1435                         */
1436                        classdesc[spClass] = currdesc;
1437                        classes[spClass] = null;
1438                    } else {
1439                        /* Current class descriptor matches current class.
1440                         * Some classes may have been inserted.
1441                         * Record the match and advance the class, continue
1442                         * with the next descriptor.
1443                         */
1444                        classdesc[spClass] = currdesc;
1445                        classes[spClass] = cl;
1446                        currclass = cl.getSuperclass();
1447                    }
1448                } // end : for (currdesc = currentClassDesc, currclass = currentClass;
1449
1450                /* Allocate a new object.
1451                 */
1452                try {
1453                    currentObject = (currentClass == null) ?
1454                        null : currentClassDesc.newInstance();
1455
1456                    // Store this object and its beginning position
1457                    // since there might be indirections to it while
1458                    // it's been unmarshalled.
1459                    activeRecursionMgr.addObject(offset, currentObject);
1460                } catch (InvocationTargetException e) {
1461                    InvalidClassException exc = new InvalidClassException(
1462                        currentClass.getName(),
1463                        "InvocationTargetException accessing no-arg constructor");
1464                    exc.initCause( e ) ;
1465                    throw exc ;
1466                } catch (UnsupportedOperationException e) {
1467                    InvalidClassException exc = new InvalidClassException(
1468                        currentClass.getName(),
1469                        "UnsupportedOperationException accessing no-arg constructor");
1470                    exc.initCause( e ) ;
1471                    throw exc ;
1472                } catch (InstantiationException e) {
1473                    InvalidClassException exc = new InvalidClassException(
1474                        currentClass.getName(),
1475                        "InstantiationException accessing no-arg constructor");
1476                    exc.initCause( e ) ;
1477                    throw exc ;
1478                }
1479
1480                Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements();
1481
1482                while((fvdsList.hasMoreElements()) && (spClass > spBase)) {
1483                    FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
1484                    // d4365188: backward compatability
1485                    String repIDForFVD = vhandler.getClassName(fvd.id);
1486                    String repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass));
1487
1488                    while ((spClass > spBase) &&
1489                           (!repIDForFVD.equals(repIDForClass))) {
1490                        int pos = findNextClass(repIDForFVD, classes, spClass, spBase);
1491                        if (pos != -1) {
1492                            spClass = pos;
1493                            currclass = currentClass = classes[spClass];
1494                            repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass));
1495                        }
1496                        else { // Read and throw away one level of the fvdslist
1497
1498                            // This seems to mean that the sender had a superclass that
1499                            // we don't have
1500
1501                            if (fvd.is_custom) {
1502
1503                                readFormatVersion();
1504                                boolean calledDefaultWriteObject = readBoolean();
1505
1506                                if (calledDefaultWriteObject)
1507                                    inputClassFields(null, null, null, fvd.members, sender);
1508
1509                                if (getStreamFormatVersion() == 2) {
1510
1511                                    ((ValueInputStream)getOrbStream()).start_value();
1512                                    ((ValueInputStream)getOrbStream()).end_value();
1513                                }
1514
1515                                // WARNING: If stream format version is 1 and there's
1516                                // optional data, we'll get some form of exception down
1517                                // the line or data corruption.
1518
1519                            } else {
1520
1521                                inputClassFields(null, currentClass, null, fvd.members, sender);
1522                            }
1523
1524                            if (fvdsList.hasMoreElements()){
1525                                fvd = (FullValueDescription)fvdsList.nextElement();
1526                                repIDForFVD = vhandler.getClassName(fvd.id);
1527                            }
1528                            else return currentObject;
1529                        }
1530                    }
1531
1532                    currdesc = currentClassDesc = ObjectStreamClass.lookup(currentClass);
1533
1534                    if (!repIDForClass.equals("java.lang.Object")) {
1535
1536                        // If the sender used custom marshaling, then it should have put
1537                        // the two bytes on the wire indicating stream format version
1538                        // and whether or not the writeObject method called
1539                        // defaultWriteObject/writeFields.
1540
1541                        ReadObjectState oldState = readObjectState;
1542                        setState(DEFAULT_STATE);
1543
1544                        try {
1545
1546                            if (fvd.is_custom) {
1547
1548                                // Read format version
1549                                readFormatVersion();
1550
1551                                // Read defaultWriteObject indicator
1552                                boolean calledDefaultWriteObject = readBoolean();
1553
1554                                readObjectState.beginUnmarshalCustomValue(this,
1555                                                                          calledDefaultWriteObject,
1556                                                                          (currentClassDesc.readObjectMethod
1557                                                                           != null));
1558                            }
1559
1560                            boolean usedReadObject = false;
1561
1562                            // Always use readObject if it exists, and fall back to default
1563                            // unmarshaling if it doesn't.
1564                            try {
1565
1566                                if (!fvd.is_custom && currentClassDesc.hasReadObject())
1567                                    setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED);
1568
1569                                // See the definition of defaultReadObjectFVDMembers
1570                                // for more information.  This concerns making sure
1571                                // we use the remote FVD's members in defaultReadObject.
1572                                defaultReadObjectFVDMembers = fvd.members;
1573                                usedReadObject = invokeObjectReader(currentClassDesc,
1574                                                                    currentObject,
1575                                                                    currentClass);
1576
1577                            } finally {
1578                                defaultReadObjectFVDMembers = null;
1579                            }
1580
1581                            // Note that the !usedReadObject !calledDefaultWriteObject
1582                            // case is handled by the beginUnmarshalCustomValue method
1583                            // of the default state
1584                            if (!usedReadObject || readObjectState == IN_READ_OBJECT_DEFAULTS_SENT)
1585                                inputClassFields(currentObject, currentClass, currdesc, fvd.members, sender);
1586
1587                            if (fvd.is_custom)
1588                                readObjectState.endUnmarshalCustomValue(this);
1589
1590                        } finally {
1591                            setState(oldState);
1592                        }
1593
1594                        currclass = currentClass = classes[--spClass];
1595
1596                    } else {
1597
1598                        // The remaining hierarchy of the local class does not match the sender's FVD.
1599                        // So, use remaining FVDs to read data off wire.  If any remaining FVDs indicate
1600                        // custom marshaling, throw MARSHAL error.
1601                        inputClassFields(null, currentClass, null, fvd.members, sender);
1602
1603                        while (fvdsList.hasMoreElements()){
1604                            fvd = (FullValueDescription)fvdsList.nextElement();
1605
1606                            if (fvd.is_custom)
1607                                skipCustomUsingFVD(fvd.members, sender);
1608                            else
1609                                inputClassFields(null, currentClass, null, fvd.members, sender);
1610                        }
1611
1612                    }
1613
1614                } // end : while(fvdsList.hasMoreElements())
1615                while (fvdsList.hasMoreElements()){
1616
1617                    FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
1618                    if (fvd.is_custom)
1619                        skipCustomUsingFVD(fvd.members, sender);
1620                    else
1621                        throwAwayData(fvd.members, sender);
1622                }
1623            }
1624
1625            return currentObject;
1626        }
1627        finally {
1628                // Make sure we exit at the same stack level as when we started.
1629                spClass = spBase;
1630
1631                // We've completed deserializing this object.  Any
1632                // future indirections will be handled correctly at the
1633                // CDR level.  The ActiveRecursionManager only deals with
1634                // objects currently being deserialized.
1635                activeRecursionMgr.removeObject(offset);
1636            }
1637
1638        }
1639
1640    /**
1641     * This input method uses FullValueDescriptions retrieved from the sender's runtime to
1642     * read in the data.  This method is capable of throwing out data not applicable to client's fields.
1643     *
1644     * NOTE : If the local description indicates custom marshaling and the remote type's FVD also
1645     * indicates custom marsahling than the local type is used to read the data off the wire.  However,
1646     * if either says custom while the other does not, a MARSHAL error is thrown.  Externalizable is
1647     * a form of custom marshaling.
1648     *
1649     */
1650    private Object skipObjectUsingFVD(String repositoryID,
1651                                      com.sun.org.omg.SendingContext.CodeBase sender)
1652        throws IOException, ClassNotFoundException
1653    {
1654
1655        Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements();
1656
1657        while(fvdsList.hasMoreElements()) {
1658            FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
1659            String repIDForFVD = vhandler.getClassName(fvd.id);
1660
1661            if (!repIDForFVD.equals("java.lang.Object")) {
1662                if (fvd.is_custom) {
1663
1664                    readFormatVersion();
1665
1666                    boolean calledDefaultWriteObject = readBoolean();
1667
1668                    if (calledDefaultWriteObject)
1669                        inputClassFields(null, null, null, fvd.members, sender);
1670
1671                    if (getStreamFormatVersion() == 2) {
1672
1673                        ((ValueInputStream)getOrbStream()).start_value();
1674                        ((ValueInputStream)getOrbStream()).end_value();
1675                    }
1676
1677                    // WARNING: If stream format version is 1 and there's
1678                    // optional data, we'll get some form of exception down
1679                    // the line.
1680
1681                } else {
1682                    // Use default marshaling
1683                    inputClassFields(null, null, null, fvd.members, sender);
1684                }
1685            }
1686
1687        } // end : while(fvdsList.hasMoreElements())
1688        return null;
1689
1690    }
1691
1692    ///////////////////
1693
1694    private int findNextClass(String classname, Class classes[], int _spClass, int _spBase){
1695
1696        for (int i = _spClass; i > _spBase; i--){
1697            if (classname.equals(classes[i].getName())) {
1698                return i;
1699            }
1700        }
1701
1702        return -1;
1703    }
1704
1705    /*
1706     * Invoke the readObject method if present.  Assumes that in the case of custom
1707     * marshaling, the format version and defaultWriteObject indicator were already
1708     * removed.
1709     */
1710    private boolean invokeObjectReader(ObjectStreamClass osc, Object obj, Class aclass)
1711        throws InvalidClassException, StreamCorruptedException,
1712               ClassNotFoundException, IOException
1713    {
1714        if (osc.readObjectMethod == null) {
1715            return false;
1716        }
1717
1718        try {
1719            osc.readObjectMethod.invoke( obj, readObjectArgList ) ;
1720            return true;
1721        } catch (InvocationTargetException e) {
1722            Throwable t = e.getTargetException();
1723            if (t instanceof ClassNotFoundException)
1724                throw (ClassNotFoundException)t;
1725            else if (t instanceof IOException)
1726                throw (IOException)t;
1727            else if (t instanceof RuntimeException)
1728                throw (RuntimeException) t;
1729            else if (t instanceof Error)
1730                throw (Error) t;
1731            else
1732                // XXX I18N, logging needed.
1733                throw new Error("internal error");
1734        } catch (IllegalAccessException e) {
1735            return false;
1736        }
1737    }
1738
1739    /*
1740     * Reset the stream to be just like it was after the constructor.
1741     */
1742    private void resetStream() throws IOException {
1743
1744        if (classes == null)
1745            classes = new Class[20];
1746        else {
1747            for (int i = 0; i < classes.length; i++)
1748                classes[i] = null;
1749        }
1750        if (classdesc == null)
1751            classdesc = new ObjectStreamClass[20];
1752        else {
1753            for (int i = 0; i < classdesc.length; i++)
1754                classdesc[i] = null;
1755        }
1756        spClass = 0;
1757
1758        if (callbacks != null)
1759            callbacks.setSize(0);       // discard any pending callbacks
1760    }
1761
1762    /**
1763     * Factored out of inputClassFields  This reads a primitive value and sets it
1764     * in the field of o described by the ObjectStreamField field.
1765     *
1766     * Note that reflection cannot be used here, because reflection cannot be used
1767     * to set final fields.
1768     */
1769    private void inputPrimitiveField(Object o, Class cl, ObjectStreamField field)
1770        throws InvalidClassException, IOException {
1771
1772        try {
1773            switch (field.getTypeCode()) {
1774                case 'B':
1775                    byte byteValue = orbStream.read_octet();
1776                    if (field.getField() != null) {
1777                        bridge.putByte( o, field.getFieldID(), byteValue ) ;
1778                        //reflective code: field.getField().setByte( o, byteValue ) ;
1779                    }
1780                    break;
1781                case 'Z':
1782                    boolean booleanValue = orbStream.read_boolean();
1783                    if (field.getField() != null) {
1784                        bridge.putBoolean( o, field.getFieldID(), booleanValue ) ;
1785                        //reflective code: field.getField().setBoolean( o, booleanValue ) ;
1786                    }
1787                    break;
1788                case 'C':
1789                    char charValue = orbStream.read_wchar();
1790                    if (field.getField() != null) {
1791                        bridge.putChar( o, field.getFieldID(), charValue ) ;
1792                        //reflective code: field.getField().setChar( o, charValue ) ;
1793                    }
1794                    break;
1795                case 'S':
1796                    short shortValue = orbStream.read_short();
1797                    if (field.getField() != null) {
1798                        bridge.putShort( o, field.getFieldID(), shortValue ) ;
1799                        //reflective code: field.getField().setShort( o, shortValue ) ;
1800                    }
1801                    break;
1802                case 'I':
1803                    int intValue = orbStream.read_long();
1804                    if (field.getField() != null) {
1805                        bridge.putInt( o, field.getFieldID(), intValue ) ;
1806                        //reflective code: field.getField().setInt( o, intValue ) ;
1807                    }
1808                    break;
1809                case 'J':
1810                    long longValue = orbStream.read_longlong();
1811                    if (field.getField() != null) {
1812                        bridge.putLong( o, field.getFieldID(), longValue ) ;
1813                        //reflective code: field.getField().setLong( o, longValue ) ;
1814                    }
1815                    break;
1816                case 'F' :
1817                    float floatValue = orbStream.read_float();
1818                    if (field.getField() != null) {
1819                        bridge.putFloat( o, field.getFieldID(), floatValue ) ;
1820                        //reflective code: field.getField().setFloat( o, floatValue ) ;
1821                    }
1822                    break;
1823                case 'D' :
1824                    double doubleValue = orbStream.read_double();
1825                    if (field.getField() != null) {
1826                        bridge.putDouble( o, field.getFieldID(), doubleValue ) ;
1827                        //reflective code: field.getField().setDouble( o, doubleValue ) ;
1828                    }
1829                    break;
1830                default:
1831                    // XXX I18N, logging needed.
1832                    throw new InvalidClassException(cl.getName());
1833            }
1834        } catch (IllegalArgumentException e) {
1835            /* This case should never happen. If the field types
1836               are not the same, InvalidClassException is raised when
1837               matching the local class to the serialized ObjectStreamClass. */
1838            ClassCastException cce = new ClassCastException("Assigning instance of class " +
1839                                         field.getType().getName() +
1840                                         " to field " +
1841                                         currentClassDesc.getName() + '#' +
1842                                         field.getField().getName());
1843            cce.initCause( e ) ;
1844            throw cce ;
1845        }
1846     }
1847
1848    private Object inputObjectField(org.omg.CORBA.ValueMember field,
1849                                    com.sun.org.omg.SendingContext.CodeBase sender)
1850        throws IndirectionException, ClassNotFoundException, IOException,
1851               StreamCorruptedException {
1852
1853        Object objectValue = null;
1854        Class type = null;
1855        String id = field.id;
1856
1857        try {
1858            type = vhandler.getClassFromType(id);
1859        } catch(ClassNotFoundException cnfe) {
1860            // Make sure type = null
1861            type = null;
1862        }
1863
1864        String signature = null;
1865        if (type != null)
1866            signature = ValueUtility.getSignature(field);
1867
1868        if (signature != null && (signature.equals("Ljava/lang/Object;") ||
1869                                  signature.equals("Ljava/io/Serializable;") ||
1870                                  signature.equals("Ljava/io/Externalizable;"))) {
1871            objectValue = javax.rmi.CORBA.Util.readAny(orbStream);
1872        } else {
1873            // Decide what method call to make based on the type. If
1874            // it is a type for which we need to load a stub, convert
1875            // the type to the correct stub type.
1876            //
1877            // NOTE : Since FullValueDescription does not allow us
1878            // to ask whether something is an interface we do not
1879            // have the ability to optimize this check.
1880
1881            int callType = ValueHandlerImpl.kValueType;
1882
1883            if (!vhandler.isSequence(id)) {
1884
1885                if (field.type.kind().value() == kRemoteTypeCode.kind().value()) {
1886
1887                    // RMI Object reference...
1888                    callType = ValueHandlerImpl.kRemoteType;
1889
1890                } else {
1891
1892                    // REVISIT.  If we don't have the local class,
1893                    // we should probably verify that it's an RMI type,
1894                    // query the remote FVD, and use is_abstract.
1895                    // Our FVD seems to get NullPointerExceptions for any
1896                    // non-RMI types.
1897
1898                    // This uses the local class in the same way as
1899                    // inputObjectField(ObjectStreamField) does.  REVISIT
1900                    // inputObjectField(ObjectStreamField)'s loadStubClass
1901                    // logic.  Assumption is that the given type cannot
1902                    // evolve to become a CORBA abstract interface or
1903                    // a RMI abstract interface.
1904
1905                    if (type != null && type.isInterface() &&
1906                        (vhandler.isAbstractBase(type) ||
1907                         ObjectStreamClassCorbaExt.isAbstractInterface(type))) {
1908
1909                        callType = ValueHandlerImpl.kAbstractType;
1910                    }
1911                }
1912            }
1913
1914            // Now that we have used the FVD of the field to determine the proper course
1915            // of action, it is ok to use the type (Class) from this point forward since
1916            // the rep. id for this read will also follow on the wire.
1917
1918            switch (callType) {
1919                case ValueHandlerImpl.kRemoteType:
1920                    if (type != null)
1921                        objectValue = Utility.readObjectAndNarrow(orbStream, type);
1922                    else
1923                        objectValue = orbStream.read_Object();
1924                    break;
1925                case ValueHandlerImpl.kAbstractType:
1926                    if (type != null)
1927                        objectValue = Utility.readAbstractAndNarrow(orbStream, type);
1928                    else
1929                        objectValue = orbStream.read_abstract_interface();
1930                    break;
1931                case ValueHandlerImpl.kValueType:
1932                    if (type != null)
1933                        objectValue = orbStream.read_value(type);
1934                    else
1935                                            objectValue = orbStream.read_value();
1936                    break;
1937                default:
1938                    // XXX I18N, logging needed.
1939                    throw new StreamCorruptedException("Unknown callType: " + callType);
1940            }
1941        }
1942
1943        return objectValue;
1944    }
1945
1946    /**
1947     * Factored out of inputClassFields and reused in
1948     * inputCurrentClassFieldsForReadFields.
1949     *
1950     * Reads the field (which of an Object type as opposed to a primitive)
1951     * described by ObjectStreamField field and returns it.
1952     */
1953    private Object inputObjectField(ObjectStreamField field)
1954        throws InvalidClassException, StreamCorruptedException,
1955               ClassNotFoundException, IndirectionException, IOException {
1956
1957        if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) {
1958            return javax.rmi.CORBA.Util.readAny(orbStream);
1959        }
1960
1961        Object objectValue = null;
1962
1963        // fields have an API to provide the actual class
1964        // corresponding to the data type
1965        // Class type = osc.forClass();
1966        Class fieldType = field.getType();
1967        Class actualType = fieldType; // This may change if stub loaded.
1968
1969        // Decide what method call to make based on the fieldType. If
1970        // it is a type for which we need to load a stub, convert
1971        // the type to the correct stub type.
1972
1973        int callType = ValueHandlerImpl.kValueType;
1974        boolean narrow = false;
1975
1976        if (fieldType.isInterface()) {
1977            boolean loadStubClass = false;
1978
1979            if (java.rmi.Remote.class.isAssignableFrom(fieldType)) {
1980
1981                // RMI Object reference...
1982                callType = ValueHandlerImpl.kRemoteType;
1983
1984            } else if (org.omg.CORBA.Object.class.isAssignableFrom(fieldType)){
1985
1986                // IDL Object reference...
1987                callType = ValueHandlerImpl.kRemoteType;
1988                loadStubClass = true;
1989
1990            } else if (vhandler.isAbstractBase(fieldType)) {
1991                // IDL Abstract Object reference...
1992
1993                callType = ValueHandlerImpl.kAbstractType;
1994                loadStubClass = true;
1995            } else if (ObjectStreamClassCorbaExt.isAbstractInterface(fieldType)) {
1996                // RMI Abstract Object reference...
1997
1998                callType = ValueHandlerImpl.kAbstractType;
1999            }
2000
2001            if (loadStubClass) {
2002                try {
2003                    String codebase = Util.getCodebase(fieldType);
2004                    String repID = vhandler.createForAnyType(fieldType);
2005                    Class stubType =
2006                        Utility.loadStubClass(repID, codebase, fieldType);
2007                    actualType = stubType;
2008                } catch (ClassNotFoundException e) {
2009                    narrow = true;
2010                }
2011            } else {
2012                narrow = true;
2013            }
2014        }
2015
2016        switch (callType) {
2017            case ValueHandlerImpl.kRemoteType:
2018                if (!narrow)
2019                    objectValue = (Object)orbStream.read_Object(actualType);
2020                else
2021                    objectValue = Utility.readObjectAndNarrow(orbStream, actualType);
2022                break;
2023            case ValueHandlerImpl.kAbstractType:
2024                if (!narrow)
2025                    objectValue = (Object)orbStream.read_abstract_interface(actualType);
2026                else
2027                    objectValue = Utility.readAbstractAndNarrow(orbStream, actualType);
2028                break;
2029            case ValueHandlerImpl.kValueType:
2030                objectValue = (Object)orbStream.read_value(actualType);
2031                break;
2032            default:
2033                // XXX I18N, logging needed.
2034                throw new StreamCorruptedException("Unknown callType: " + callType);
2035        }
2036
2037        return objectValue;
2038    }
2039
2040    private final boolean mustUseRemoteValueMembers() {
2041        return defaultReadObjectFVDMembers != null;
2042    }
2043
2044    void readFields(java.util.Map fieldToValueMap)
2045        throws InvalidClassException, StreamCorruptedException,
2046               ClassNotFoundException, IOException {
2047
2048        if (mustUseRemoteValueMembers()) {
2049            inputRemoteMembersForReadFields(fieldToValueMap);
2050        } else
2051            inputCurrentClassFieldsForReadFields(fieldToValueMap);
2052    }
2053
2054    private final void inputRemoteMembersForReadFields(java.util.Map fieldToValueMap)
2055        throws InvalidClassException, StreamCorruptedException,
2056               ClassNotFoundException, IOException {
2057
2058        // Must have this local variable since defaultReadObjectFVDMembers
2059        // may get mangled by recursion.
2060        ValueMember fields[] = defaultReadObjectFVDMembers;
2061
2062        try {
2063
2064            for (int i = 0; i < fields.length; i++) {
2065
2066                switch (fields[i].type.kind().value()) {
2067
2068                case TCKind._tk_octet:
2069                    byte byteValue = orbStream.read_octet();
2070                    fieldToValueMap.put(fields[i].name, new Byte(byteValue));
2071                    break;
2072                case TCKind._tk_boolean:
2073                    boolean booleanValue = orbStream.read_boolean();
2074                    fieldToValueMap.put(fields[i].name, new Boolean(booleanValue));
2075                    break;
2076                case TCKind._tk_char:
2077                    // Backwards compatibility.  Older Sun ORBs sent
2078                    // _tk_char even though they read and wrote wchars
2079                    // correctly.
2080                    //
2081                    // Fall through to the _tk_wchar case.
2082                case TCKind._tk_wchar:
2083                    char charValue = orbStream.read_wchar();
2084                    fieldToValueMap.put(fields[i].name, new Character(charValue));
2085                    break;
2086                case TCKind._tk_short:
2087                    short shortValue = orbStream.read_short();
2088                    fieldToValueMap.put(fields[i].name, new Short(shortValue));
2089                    break;
2090                case TCKind._tk_long:
2091                    int intValue = orbStream.read_long();
2092                    fieldToValueMap.put(fields[i].name, new Integer(intValue));
2093                    break;
2094                case TCKind._tk_longlong:
2095                    long longValue = orbStream.read_longlong();
2096                    fieldToValueMap.put(fields[i].name, new Long(longValue));
2097                    break;
2098                case TCKind._tk_float:
2099                    float floatValue = orbStream.read_float();
2100                    fieldToValueMap.put(fields[i].name, new Float(floatValue));
2101                    break;
2102                case TCKind._tk_double:
2103                    double doubleValue = orbStream.read_double();
2104                    fieldToValueMap.put(fields[i].name, new Double(doubleValue));
2105                    break;
2106                case TCKind._tk_value:
2107                case TCKind._tk_objref:
2108                case TCKind._tk_value_box:
2109                    Object objectValue = null;
2110                    try {
2111                        objectValue = inputObjectField(fields[i],
2112                                                       cbSender);
2113
2114                    } catch (IndirectionException cdrie) {
2115                        // The CDR stream had never seen the given offset before,
2116                        // so check the recursion manager (it will throw an
2117                        // IOException if it doesn't have a reference, either).
2118                        objectValue = activeRecursionMgr.getObject(cdrie.offset);
2119                    }
2120
2121                    fieldToValueMap.put(fields[i].name, objectValue);
2122                    break;
2123                default:
2124                    // XXX I18N, logging needed.
2125                    throw new StreamCorruptedException("Unknown kind: "
2126                                                       + fields[i].type.kind().value());
2127                }
2128            }
2129        } catch (Throwable t) {
2130            StreamCorruptedException result = new StreamCorruptedException(t.getMessage());
2131            result.initCause(t);
2132            throw result;
2133        }
2134    }
2135
2136    /**
2137     * Called from InputStreamHook.
2138     *
2139     * Reads the fields of the current class (could be the ones
2140     * queried from the remote FVD) and puts them in
2141     * the given Map, name to value.  Wraps primitives in the
2142     * corresponding java.lang Objects.
2143     */
2144    private final void inputCurrentClassFieldsForReadFields(java.util.Map fieldToValueMap)
2145        throws InvalidClassException, StreamCorruptedException,
2146               ClassNotFoundException, IOException {
2147
2148        ObjectStreamField[] fields = currentClassDesc.getFieldsNoCopy();
2149
2150        int primFields = fields.length - currentClassDesc.objFields;
2151
2152        // Handle the primitives first
2153        for (int i = 0; i < primFields; ++i) {
2154
2155            switch (fields[i].getTypeCode()) {
2156                case 'B':
2157                    byte byteValue = orbStream.read_octet();
2158                    fieldToValueMap.put(fields[i].getName(),
2159                                        new Byte(byteValue));
2160                    break;
2161                case 'Z':
2162                   boolean booleanValue = orbStream.read_boolean();
2163                   fieldToValueMap.put(fields[i].getName(),
2164                                       new Boolean(booleanValue));
2165                   break;
2166                case 'C':
2167                    char charValue = orbStream.read_wchar();
2168                    fieldToValueMap.put(fields[i].getName(),
2169                                        new Character(charValue));
2170                    break;
2171                case 'S':
2172                    short shortValue = orbStream.read_short();
2173                    fieldToValueMap.put(fields[i].getName(),
2174                                        new Short(shortValue));
2175                    break;
2176                case 'I':
2177                    int intValue = orbStream.read_long();
2178                    fieldToValueMap.put(fields[i].getName(),
2179                                        new Integer(intValue));
2180                    break;
2181                case 'J':
2182                    long longValue = orbStream.read_longlong();
2183                    fieldToValueMap.put(fields[i].getName(),
2184                                        new Long(longValue));
2185                    break;
2186                case 'F' :
2187                    float floatValue = orbStream.read_float();
2188                    fieldToValueMap.put(fields[i].getName(),
2189                                        new Float(floatValue));
2190                    break;
2191                case 'D' :
2192                    double doubleValue = orbStream.read_double();
2193                    fieldToValueMap.put(fields[i].getName(),
2194                                        new Double(doubleValue));
2195                    break;
2196                default:
2197                    // XXX I18N, logging needed.
2198                    throw new InvalidClassException(currentClassDesc.getName());
2199            }
2200        }
2201
2202        /* Read and set object fields from the input stream. */
2203        if (currentClassDesc.objFields > 0) {
2204            for (int i = primFields; i < fields.length; i++) {
2205                Object objectValue = null;
2206                try {
2207                    objectValue = inputObjectField(fields[i]);
2208                } catch(IndirectionException cdrie) {
2209                    // The CDR stream had never seen the given offset before,
2210                    // so check the recursion manager (it will throw an
2211                    // IOException if it doesn't have a reference, either).
2212                    objectValue = activeRecursionMgr.getObject(cdrie.offset);
2213                }
2214
2215                fieldToValueMap.put(fields[i].getName(), objectValue);
2216            }
2217        }
2218    }
2219
2220    /*
2221     * Read the fields of the specified class from the input stream and set
2222     * the values of the fields in the specified object. If the specified
2223     * object is null, just consume the fields without setting any values. If
2224     * any ObjectStreamField does not have a reflected Field, don't try to set
2225     * that field in the object.
2226     *
2227     * REVISIT -- This code doesn't do what the comment says to when
2228     * getField() is null!
2229     */
2230    private void inputClassFields(Object o, Class cl,
2231                                  ObjectStreamField[] fields,
2232                                  com.sun.org.omg.SendingContext.CodeBase sender)
2233        throws InvalidClassException, StreamCorruptedException,
2234               ClassNotFoundException, IOException
2235    {
2236
2237        int primFields = fields.length - currentClassDesc.objFields;
2238
2239        if (o != null) {
2240            for (int i = 0; i < primFields; ++i) {
2241                inputPrimitiveField(o, cl, fields[i]);
2242            }
2243        }
2244
2245        /* Read and set object fields from the input stream. */
2246        if (currentClassDesc.objFields > 0) {
2247            for (int i = primFields; i < fields.length; i++) {
2248                Object objectValue = null;
2249
2250                try {
2251                    objectValue = inputObjectField(fields[i]);
2252                } catch(IndirectionException cdrie) {
2253                    // The CDR stream had never seen the given offset before,
2254                    // so check the recursion manager (it will throw an
2255                    // IOException if it doesn't have a reference, either).
2256                    objectValue = activeRecursionMgr.getObject(cdrie.offset);
2257                }
2258
2259                if ((o == null) || (fields[i].getField() == null)) {
2260                    continue;
2261                }
2262
2263                try {
2264                    Class fieldCl = fields[i].getClazz();
2265                    if ((objectValue != null)
2266                            && (!fieldCl.isAssignableFrom(
2267                                    objectValue.getClass()))) {
2268                        throw new IllegalArgumentException("Field mismatch");
2269                    }
2270                   Field classField = null;
2271                    try {
2272                        classField = cl.getDeclaredField(fields[i].getName());
2273                    } catch (NoSuchFieldException nsfEx) {
2274                        throw new IllegalArgumentException(nsfEx);
2275                    } catch (SecurityException secEx) {
2276                        throw new IllegalArgumentException(secEx.getCause());
2277                    }
2278                    Class<?> declaredFieldClass = classField.getType();
2279
2280                    // check input field type is a declared field type
2281                    // input field is a subclass of the declared field
2282                    if (!declaredFieldClass.isAssignableFrom(fieldCl)) {
2283                        throw new IllegalArgumentException(
2284                                "Field Type mismatch");
2285                    }
2286                    if (objectValue != null && !fieldCl.isInstance(objectValue)) {
2287                        throw new IllegalArgumentException();
2288                    }
2289                    bridge.putObject( o, fields[i].getFieldID(), objectValue ) ;
2290                    // reflective code: fields[i].getField().set( o, objectValue ) ;
2291                } catch (IllegalArgumentException e) {
2292                    ClassCastException exc = new ClassCastException("Assigning instance of class " +
2293                                                 objectValue.getClass().getName() +
2294                                                 " to field " +
2295                                                 currentClassDesc.getName() +
2296                                                 '#' +
2297                                                 fields[i].getField().getName());
2298                    exc.initCause( e ) ;
2299                    throw exc ;
2300                }
2301            } // end : for loop
2302            }
2303        }
2304
2305    /*
2306     * Read the fields of the specified class from the input stream and set
2307     * the values of the fields in the specified object. If the specified
2308     * object is null, just consume the fields without setting any values. If
2309     * any ObjectStreamField does not have a reflected Field, don't try to set
2310     * that field in the object.
2311     */
2312    private void inputClassFields(Object o, Class cl,
2313                                  ObjectStreamClass osc,
2314                                  ValueMember[] fields,
2315                                  com.sun.org.omg.SendingContext.CodeBase sender)
2316        throws InvalidClassException, StreamCorruptedException,
2317               ClassNotFoundException, IOException
2318    {
2319        try{
2320            for (int i = 0; i < fields.length; ++i) {
2321                try {
2322                    switch (fields[i].type.kind().value()) {
2323                    case TCKind._tk_octet:
2324                        byte byteValue = orbStream.read_octet();
2325                        if ((o != null) && osc.hasField(fields[i]))
2326                        setByteField(o, cl, fields[i].name, byteValue);
2327                        break;
2328                    case TCKind._tk_boolean:
2329                        boolean booleanValue = orbStream.read_boolean();
2330                        if ((o != null) && osc.hasField(fields[i]))
2331                        setBooleanField(o, cl, fields[i].name, booleanValue);
2332                        break;
2333                    case TCKind._tk_char:
2334                        // Backwards compatibility.  Older Sun ORBs sent
2335                        // _tk_char even though they read and wrote wchars
2336                        // correctly.
2337                        //
2338                        // Fall through to the _tk_wchar case.
2339                    case TCKind._tk_wchar:
2340                        char charValue = orbStream.read_wchar();
2341                        if ((o != null) && osc.hasField(fields[i]))
2342                        setCharField(o, cl, fields[i].name, charValue);
2343                        break;
2344                    case TCKind._tk_short:
2345                        short shortValue = orbStream.read_short();
2346                        if ((o != null) && osc.hasField(fields[i]))
2347                        setShortField(o, cl, fields[i].name, shortValue);
2348                        break;
2349                    case TCKind._tk_long:
2350                        int intValue = orbStream.read_long();
2351                        if ((o != null) && osc.hasField(fields[i]))
2352                        setIntField(o, cl, fields[i].name, intValue);
2353                        break;
2354                    case TCKind._tk_longlong:
2355                        long longValue = orbStream.read_longlong();
2356                        if ((o != null) && osc.hasField(fields[i]))
2357                        setLongField(o, cl, fields[i].name, longValue);
2358                        break;
2359                    case TCKind._tk_float:
2360                        float floatValue = orbStream.read_float();
2361                        if ((o != null) && osc.hasField(fields[i]))
2362                        setFloatField(o, cl, fields[i].name, floatValue);
2363                        break;
2364                    case TCKind._tk_double:
2365                        double doubleValue = orbStream.read_double();
2366                        if ((o != null) && osc.hasField(fields[i]))
2367                        setDoubleField(o, cl, fields[i].name, doubleValue);
2368                        break;
2369                    case TCKind._tk_value:
2370                    case TCKind._tk_objref:
2371                    case TCKind._tk_value_box:
2372                        Object objectValue = null;
2373                        try {
2374                            objectValue = inputObjectField(fields[i], sender);
2375                        } catch (IndirectionException cdrie) {
2376                            // The CDR stream had never seen the given offset before,
2377                            // so check the recursion manager (it will throw an
2378                            // IOException if it doesn't have a reference, either).
2379                            objectValue = activeRecursionMgr.getObject(cdrie.offset);
2380                        }
2381
2382                        if (o == null)
2383                            continue;
2384                        try {
2385                            if (osc.hasField(fields[i])){
2386                                setObjectField(o,
2387                                               cl,
2388                                               fields[i].name,
2389                                               objectValue);
2390                            } else {
2391                                // REVISIT.  Convert to a log message.
2392                                // This is a normal case when fields have
2393                                // been added as part of evolution, but
2394                                // silently skipping can make it hard to
2395                                // debug if there's an error
2396//                                 System.out.println("**** warning, not setting field: "
2397//                                                    + fields[i].name
2398//                                                    + " since not on class "
2399//                                                    + osc.getName());
2400
2401                            }
2402                        } catch (IllegalArgumentException e) {
2403                            // XXX I18N, logging needed.
2404                            ClassCastException cce = new ClassCastException("Assigning instance of class " +
2405                                objectValue.getClass().getName() + " to field " + fields[i].name);
2406                            cce.initCause(e) ;
2407                            throw cce ;
2408                        }
2409                        break;
2410                    default:
2411                        // XXX I18N, logging needed.
2412                        throw new StreamCorruptedException("Unknown kind: "
2413                                                           + fields[i].type.kind().value());
2414                    }
2415                } catch (IllegalArgumentException e) {
2416                    /* This case should never happen. If the field types
2417                       are not the same, InvalidClassException is raised when
2418                       matching the local class to the serialized ObjectStreamClass. */
2419                    // XXX I18N, logging needed.
2420                    ClassCastException cce = new ClassCastException("Assigning instance of class " + fields[i].id +
2421                        " to field " + currentClassDesc.getName() + '#' + fields[i].name);
2422                    cce.initCause( e ) ;
2423                    throw cce ;
2424                }
2425            }
2426        } catch(Throwable t){
2427            // XXX I18N, logging needed.
2428            StreamCorruptedException sce = new StreamCorruptedException(t.getMessage());
2429            sce.initCause(t) ;
2430            throw sce ;
2431        }
2432    }
2433
2434    private void skipCustomUsingFVD(ValueMember[] fields,
2435                                    com.sun.org.omg.SendingContext.CodeBase sender)
2436                                    throws InvalidClassException, StreamCorruptedException,
2437                                           ClassNotFoundException, IOException
2438    {
2439        readFormatVersion();
2440        boolean calledDefaultWriteObject = readBoolean();
2441
2442        if (calledDefaultWriteObject)
2443            throwAwayData(fields, sender);
2444
2445        if (getStreamFormatVersion() == 2) {
2446
2447            ((ValueInputStream)getOrbStream()).start_value();
2448            ((ValueInputStream)getOrbStream()).end_value();
2449        }
2450    }
2451
2452    /*
2453     * Read the fields of the specified class from the input stream throw data away.
2454     * This must handle same switch logic as above.
2455     */
2456    private void throwAwayData(ValueMember[] fields,
2457                               com.sun.org.omg.SendingContext.CodeBase sender)
2458        throws InvalidClassException, StreamCorruptedException,
2459               ClassNotFoundException, IOException {
2460
2461        for (int i = 0; i < fields.length; ++i) {
2462
2463            try {
2464
2465                switch (fields[i].type.kind().value()) {
2466                case TCKind._tk_octet:
2467                    orbStream.read_octet();
2468                    break;
2469                case TCKind._tk_boolean:
2470                    orbStream.read_boolean();
2471                    break;
2472                case TCKind._tk_char:
2473                    // Backwards compatibility.  Older Sun ORBs sent
2474                    // _tk_char even though they read and wrote wchars
2475                    // correctly.
2476                    //
2477                    // Fall through to the _tk_wchar case.
2478                case TCKind._tk_wchar:
2479                    orbStream.read_wchar();
2480                    break;
2481                case TCKind._tk_short:
2482                    orbStream.read_short();
2483                    break;
2484                case TCKind._tk_long:
2485                    orbStream.read_long();
2486                    break;
2487                case TCKind._tk_longlong:
2488                    orbStream.read_longlong();
2489                    break;
2490                case TCKind._tk_float:
2491                    orbStream.read_float();
2492                    break;
2493                case TCKind._tk_double:
2494                    orbStream.read_double();
2495                    break;
2496                case TCKind._tk_value:
2497                case TCKind._tk_objref:
2498                case TCKind._tk_value_box:
2499                    Class type = null;
2500                    String id = fields[i].id;
2501
2502                    try {
2503                        type = vhandler.getClassFromType(id);
2504                    }
2505                    catch(ClassNotFoundException cnfe){
2506                        // Make sure type = null
2507                        type = null;
2508                    }
2509                    String signature = null;
2510                    if (type != null)
2511                        signature = ValueUtility.getSignature(fields[i]);
2512
2513                    // Read value
2514                    try {
2515                        if ((signature != null) && ( signature.equals("Ljava/lang/Object;") ||
2516                                                     signature.equals("Ljava/io/Serializable;") ||
2517                                                     signature.equals("Ljava/io/Externalizable;")) ) {
2518                            javax.rmi.CORBA.Util.readAny(orbStream);
2519                        }
2520                        else {
2521                            // Decide what method call to make based on the type.
2522                            //
2523                            // NOTE : Since FullValueDescription does not allow us
2524                            // to ask whether something is an interface we do not
2525                            // have the ability to optimize this check.
2526
2527                            int callType = ValueHandlerImpl.kValueType;
2528
2529                            if (!vhandler.isSequence(id)) {
2530                                FullValueDescription fieldFVD = sender.meta(fields[i].id);
2531                                if (kRemoteTypeCode == fields[i].type) {
2532
2533                                    // RMI Object reference...
2534                                    callType = ValueHandlerImpl.kRemoteType;
2535                                } else if (fieldFVD.is_abstract) {
2536                                    // RMI Abstract Object reference...
2537
2538                                    callType = ValueHandlerImpl.kAbstractType;
2539                                }
2540                            }
2541
2542                            // Now that we have used the FVD of the field to determine the proper course
2543                            // of action, it is ok to use the type (Class) from this point forward since
2544                            // the rep. id for this read will also follow on the wire.
2545
2546                            switch (callType) {
2547                            case ValueHandlerImpl.kRemoteType:
2548                                orbStream.read_Object();
2549                                break;
2550                            case ValueHandlerImpl.kAbstractType:
2551                                orbStream.read_abstract_interface();
2552                                break;
2553                            case ValueHandlerImpl.kValueType:
2554                                if (type != null) {
2555                                    orbStream.read_value(type);
2556                                } else {
2557                                    orbStream.read_value();
2558                                }
2559                                break;
2560                            default:
2561                                // XXX I18N, logging needed.
2562                                throw new StreamCorruptedException("Unknown callType: "
2563                                                                   + callType);
2564                            }
2565                        }
2566
2567                    }
2568                    catch(IndirectionException cdrie) {
2569                        // Since we are throwing this away, don't bother handling recursion.
2570                        continue;
2571                    }
2572
2573                    break;
2574                default:
2575                    // XXX I18N, logging needed.
2576                    throw new StreamCorruptedException("Unknown kind: "
2577                                                       + fields[i].type.kind().value());
2578
2579                }
2580            } catch (IllegalArgumentException e) {
2581                /* This case should never happen. If the field types
2582                   are not the same, InvalidClassException is raised when
2583                   matching the local class to the serialized ObjectStreamClass. */
2584                // XXX I18N, logging needed.
2585                ClassCastException cce = new ClassCastException("Assigning instance of class " +
2586                    fields[i].id + " to field " + currentClassDesc.getName() +
2587                    '#' + fields[i].name);
2588                cce.initCause(e) ;
2589                throw cce ;
2590            }
2591        }
2592
2593    }
2594
2595    private static void setObjectField(Object o, Class c, String fieldName, Object v) {
2596        try {
2597            Field fld = c.getDeclaredField( fieldName ) ;
2598            Class fieldCl = fld.getType();
2599            if(v != null && !fieldCl.isInstance(v)) {
2600                throw new Exception();
2601            }
2602            long key = bridge.objectFieldOffset( fld ) ;
2603            bridge.putObject( o, key, v ) ;
2604        } catch (Exception e) {
2605            if (o != null) {
2606                throw utilWrapper.errorSetObjectField( e, fieldName,
2607                    o.toString(),
2608                    v.toString() ) ;
2609            } else {
2610                throw utilWrapper.errorSetObjectField( e, fieldName,
2611                    "null " + c.getName() + " object",
2612                    v.toString() ) ;
2613            }
2614        }
2615    }
2616
2617    private static void setBooleanField(Object o, Class c, String fieldName, boolean v)
2618    {
2619        try {
2620            Field fld = c.getDeclaredField( fieldName ) ;
2621            if ((fld != null) && (fld.getType() == Boolean.TYPE)) {
2622                long key = bridge.objectFieldOffset( fld ) ;
2623                bridge.putBoolean( o, key, v ) ;
2624            } else {
2625                throw new InvalidObjectException("Field Type mismatch");
2626            }
2627        } catch (Exception e) {
2628            if (o != null) {
2629            throw utilWrapper.errorSetBooleanField( e, fieldName,
2630                o.toString(),
2631                new Boolean(v) ) ;
2632            } else {
2633                throw utilWrapper.errorSetBooleanField( e, fieldName,
2634                    "null " + c.getName() + " object",
2635                    new Boolean(v) ) ;
2636            }
2637        }
2638    }
2639
2640    private static void setByteField(Object o, Class c, String fieldName, byte v)
2641    {
2642        try {
2643            Field fld = c.getDeclaredField( fieldName ) ;
2644            if ((fld != null) && (fld.getType() == Byte.TYPE)) {
2645                long key = bridge.objectFieldOffset( fld ) ;
2646                bridge.putByte( o, key, v ) ;
2647            } else {
2648                throw new InvalidObjectException("Field Type mismatch");
2649            }
2650        } catch (Exception e) {
2651            if (o != null) {
2652                throw utilWrapper.errorSetByteField( e, fieldName,
2653                    o.toString(),
2654                    new Byte(v) ) ;
2655            } else {
2656                throw utilWrapper.errorSetByteField( e, fieldName,
2657                    "null " + c.getName() + " object",
2658                    new Byte(v) ) ;
2659            }
2660        }
2661    }
2662
2663    private static void setCharField(Object o, Class c, String fieldName, char v)
2664    {
2665        try {
2666            Field fld = c.getDeclaredField( fieldName ) ;
2667            if ((fld != null) && (fld.getType() == Character.TYPE)) {
2668                long key = bridge.objectFieldOffset( fld ) ;
2669                bridge.putChar( o, key, v ) ;
2670            } else {
2671                throw new InvalidObjectException("Field Type mismatch");
2672            }
2673        } catch (Exception e) {
2674            if (o != null) {
2675                throw utilWrapper.errorSetCharField( e, fieldName,
2676                    o.toString(),
2677                    new Character(v) ) ;
2678            } else {
2679                throw utilWrapper.errorSetCharField( e, fieldName,
2680                    "null " + c.getName() + " object",
2681                    new Character(v) ) ;
2682            }
2683        }
2684    }
2685
2686    private static void setShortField(Object o, Class c, String fieldName, short v)
2687    {
2688        try {
2689            Field fld = c.getDeclaredField( fieldName ) ;
2690            if ((fld != null) && (fld.getType() == Short.TYPE)) {
2691                long key = bridge.objectFieldOffset( fld ) ;
2692                bridge.putShort( o, key, v ) ;
2693            } else {
2694                throw new InvalidObjectException("Field Type mismatch");
2695            }
2696        } catch (Exception e) {
2697            if (o != null) {
2698            throw utilWrapper.errorSetShortField( e, fieldName,
2699                o.toString(),
2700                new Short(v) ) ;
2701            } else {
2702                throw utilWrapper.errorSetShortField( e, fieldName,
2703                    "null " + c.getName() + " object",
2704                    new Short(v) ) ;
2705            }
2706        }
2707    }
2708
2709    private static void setIntField(Object o, Class c, String fieldName, int v)
2710    {
2711        try {
2712            Field fld = c.getDeclaredField( fieldName ) ;
2713            if ((fld != null) && (fld.getType() == Integer.TYPE)) {
2714                long key = bridge.objectFieldOffset( fld ) ;
2715                bridge.putInt( o, key, v ) ;
2716            } else {
2717                throw new InvalidObjectException("Field Type mismatch");
2718            }
2719        } catch (Exception e) {
2720            if (o != null) {
2721                throw utilWrapper.errorSetIntField( e, fieldName,
2722                    o.toString(),
2723                    new Integer(v) ) ;
2724            } else {
2725                throw utilWrapper.errorSetIntField( e, fieldName,
2726                    "null " + c.getName() + " object",
2727                    new Integer(v) ) ;
2728            }
2729        }
2730    }
2731
2732    private static void setLongField(Object o, Class c, String fieldName, long v)
2733    {
2734        try {
2735            Field fld = c.getDeclaredField( fieldName ) ;
2736            if ((fld != null) && (fld.getType() == Long.TYPE)) {
2737                long key = bridge.objectFieldOffset( fld ) ;
2738                bridge.putLong( o, key, v ) ;
2739            } else {
2740                throw new InvalidObjectException("Field Type mismatch");
2741            }
2742        } catch (Exception e) {
2743            if (o != null) {
2744                throw utilWrapper.errorSetLongField( e, fieldName,
2745                    o.toString(),
2746                    new Long(v) ) ;
2747            } else {
2748                throw utilWrapper.errorSetLongField( e, fieldName,
2749                    "null " + c.getName() + " object",
2750                    new Long(v) ) ;
2751            }
2752        }
2753    }
2754
2755    private static void setFloatField(Object o, Class c, String fieldName, float v)
2756    {
2757        try {
2758            Field fld = c.getDeclaredField( fieldName ) ;
2759            if ((fld != null) && (fld.getType() == Float.TYPE)) {
2760                long key = bridge.objectFieldOffset( fld ) ;
2761                bridge.putFloat( o, key, v ) ;
2762            } else {
2763                throw new InvalidObjectException("Field Type mismatch");
2764            }
2765        } catch (Exception e) {
2766            if (o != null) {
2767                throw utilWrapper.errorSetFloatField( e, fieldName,
2768                    o.toString(),
2769                    new Float(v) ) ;
2770            } else {
2771                throw utilWrapper.errorSetFloatField( e, fieldName,
2772                    "null " + c.getName() + " object",
2773                    new Float(v) ) ;
2774            }
2775        }
2776    }
2777
2778    private static void setDoubleField(Object o, Class c, String fieldName, double v)
2779    {
2780        try {
2781            Field fld = c.getDeclaredField( fieldName ) ;
2782            if ((fld != null) && (fld.getType() == Double.TYPE)) {
2783                long key = bridge.objectFieldOffset( fld ) ;
2784                bridge.putDouble( o, key, v ) ;
2785            } else {
2786                throw new InvalidObjectException("Field Type mismatch");
2787            }
2788        } catch (Exception e) {
2789            if (o != null) {
2790                throw utilWrapper.errorSetDoubleField( e, fieldName,
2791                    o.toString(),
2792                    new Double(v) ) ;
2793            } else {
2794                throw utilWrapper.errorSetDoubleField( e, fieldName,
2795                    "null " + c.getName() + " object",
2796                    new Double(v) ) ;
2797            }
2798        }
2799    }
2800
2801    /**
2802     * This class maintains a map of stream position to
2803     * an Object currently being deserialized.  It is used
2804     * to handle the cases where the are indirections to
2805     * an object on the recursion stack.  The CDR level
2806     * handles indirections to objects previously seen
2807     * (and completely deserialized) in the stream.
2808     */
2809    static class ActiveRecursionManager
2810    {
2811        private Map offsetToObjectMap;
2812
2813        public ActiveRecursionManager() {
2814            // A hash map is unsynchronized and allows
2815            // null values
2816            offsetToObjectMap = new HashMap();
2817        }
2818
2819        // Called right after allocating a new object.
2820        // Offset is the starting position in the stream
2821        // of the object.
2822        public void addObject(int offset, Object value) {
2823            offsetToObjectMap.put(new Integer(offset), value);
2824        }
2825
2826        // If the given starting position doesn't refer
2827        // to the beginning of an object currently being
2828        // deserialized, this throws an IOException.
2829        // Otherwise, it returns a reference to the
2830        // object.
2831        public Object getObject(int offset) throws IOException {
2832            Integer position = new Integer(offset);
2833
2834            if (!offsetToObjectMap.containsKey(position))
2835                // XXX I18N, logging needed.
2836                throw new IOException("Invalid indirection to offset "
2837                                      + offset);
2838
2839            return offsetToObjectMap.get(position);
2840        }
2841
2842        // Called when an object has been completely
2843        // deserialized, so it should no longer be in
2844        // this mapping.  The CDR level can handle
2845        // further indirections.
2846        public void removeObject(int offset) {
2847            offsetToObjectMap.remove(new Integer(offset));
2848        }
2849
2850        // If the given offset doesn't map to an Object,
2851        // then it isn't an indirection to an object
2852        // currently being deserialized.
2853        public boolean containsObject(int offset) {
2854            return offsetToObjectMap.containsKey(new Integer(offset));
2855        }
2856    }
2857}
2858