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