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