| /* |
| * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| /* |
| * Licensed Materials - Property of IBM |
| * RMI-IIOP v1.0 |
| * Copyright IBM Corp. 1998 1999 All Rights Reserved |
| * |
| */ |
| |
| package com.sun.corba.se.impl.io; |
| |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.io.StreamCorruptedException; |
| import java.io.ObjectInputValidation; |
| import java.io.NotActiveException; |
| import java.io.InvalidObjectException; |
| import java.io.InvalidClassException; |
| import java.io.DataInputStream; |
| import java.io.OptionalDataException; |
| import java.io.WriteAbortedException; |
| import java.io.Externalizable; |
| import java.io.EOFException; |
| import java.lang.reflect.*; |
| import java.util.Vector; |
| import java.util.Stack; |
| import java.util.Hashtable; |
| import java.util.Enumeration; |
| |
| import sun.corba.Bridge ; |
| |
| import java.security.AccessController ; |
| import java.security.PrivilegedAction ; |
| |
| import com.sun.corba.se.impl.io.ObjectStreamClass; |
| import com.sun.corba.se.impl.util.Utility; |
| |
| import org.omg.CORBA.portable.ValueInputStream; |
| |
| import org.omg.CORBA.ValueMember; |
| import org.omg.CORBA.SystemException; |
| import org.omg.CORBA.TCKind; |
| import org.omg.CORBA.ORB; |
| import org.omg.CORBA.CompletionStatus; |
| import org.omg.CORBA.portable.IndirectionException; |
| import org.omg.CORBA.MARSHAL; |
| import org.omg.CORBA.TypeCode; |
| |
| import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription; |
| import com.sun.org.omg.SendingContext.CodeBase; |
| |
| import javax.rmi.PortableRemoteObject; |
| import javax.rmi.CORBA.Util; |
| import javax.rmi.CORBA.ValueHandler; |
| |
| import java.security.*; |
| import java.util.*; |
| |
| import com.sun.corba.se.impl.orbutil.ObjectUtility ; |
| import com.sun.corba.se.impl.logging.OMGSystemException ; |
| import com.sun.corba.se.impl.logging.UtilSystemException ; |
| |
| import com.sun.corba.se.spi.logging.CORBALogDomains ; |
| |
| /** |
| * IIOPInputStream is used by the ValueHandlerImpl to handle Java serialization |
| * input semantics. |
| * |
| * @author Stephen Lewallen |
| * @since JDK1.1.6 |
| */ |
| |
| public class IIOPInputStream |
| extends com.sun.corba.se.impl.io.InputStreamHook |
| { |
| private static Bridge bridge = |
| (Bridge)AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return Bridge.get() ; |
| } |
| } |
| ) ; |
| |
| private static OMGSystemException omgWrapper = OMGSystemException.get( |
| CORBALogDomains.RPC_ENCODING ) ; |
| private static UtilSystemException utilWrapper = UtilSystemException.get( |
| CORBALogDomains.RPC_ENCODING ) ; |
| |
| // Necessary to pass the appropriate fields into the |
| // defaultReadObjectDelegate method (which takes no |
| // parameters since it's called from |
| // java.io.ObjectInpuStream defaultReadObject() |
| // which we can't change). |
| // |
| // This is only used in the case where the fields had |
| // to be obtained remotely because of a serializable |
| // version difference. Set in inputObjectUsingFVD. |
| // Part of serialization evolution fixes for Ladybird, |
| // bug 4365188. |
| private ValueMember defaultReadObjectFVDMembers[] = null; |
| |
| private org.omg.CORBA_2_3.portable.InputStream orbStream; |
| |
| private CodeBase cbSender; |
| |
| private ValueHandlerImpl vhandler; //d4365188 |
| |
| private Object currentObject = null; |
| |
| private ObjectStreamClass currentClassDesc = null; |
| |
| private Class currentClass = null; |
| |
| private int recursionDepth = 0; |
| |
| private int simpleReadDepth = 0; |
| |
| // The ActiveRecursionManager replaces the old RecursionManager which |
| // used to record how many recursions were made, and resolve them after |
| // an object was completely deserialized. |
| // |
| // That created problems (as in bug 4414154) because when custom |
| // unmarshaling in readObject, there can be recursive references |
| // to one of the objects currently being unmarshaled, and the |
| // passive recursion system failed. |
| ActiveRecursionManager activeRecursionMgr = new ActiveRecursionManager(); |
| |
| private IOException abortIOException = null; |
| |
| /* Remember the first exception that stopped this stream. */ |
| private ClassNotFoundException abortClassNotFoundException = null; |
| |
| /* Vector of validation callback objects |
| * The vector is created as needed. The vector is maintained in |
| * order of highest (first) priority to lowest |
| */ |
| private Vector callbacks; |
| |
| // Serialization machinery fields |
| /* Arrays used to keep track of classes and ObjectStreamClasses |
| * as they are being merged; used in inputObject. |
| * spClass is the stack pointer for both. */ |
| ObjectStreamClass[] classdesc; |
| Class[] classes; |
| int spClass; |
| |
| private static final String kEmptyStr = ""; |
| |
| // TCKind TypeCodes used in FVD inputClassFields |
| //public static final TypeCode kRemoteTypeCode = new TypeCodeImpl(TCKind._tk_objref); |
| //public static final TypeCode kValueTypeCode = new TypeCodeImpl(TCKind._tk_value); |
| // removed TypeCodeImpl dependency |
| public static final TypeCode kRemoteTypeCode = ORB.init().get_primitive_tc(TCKind.tk_objref); |
| public static final TypeCode kValueTypeCode = ORB.init().get_primitive_tc(TCKind.tk_value); |
| |
| // TESTING CODE - useFVDOnly should be made final before FCS in order to |
| // optimize out the check. |
| private static final boolean useFVDOnly = false; |
| |
| private byte streamFormatVersion; |
| |
| // Since java.io.OptionalDataException's constructors are |
| // package private, but we need to throw it in some special |
| // cases, we try to do it by reflection. |
| private static final Constructor OPT_DATA_EXCEPTION_CTOR; |
| |
| private Object[] readObjectArgList = { this } ; |
| |
| static { |
| OPT_DATA_EXCEPTION_CTOR = getOptDataExceptionCtor(); |
| } |
| |
| // Grab the OptionalDataException boolean ctor and make |
| // it accessible. Note that any exceptions |
| // will be wrapped in ExceptionInInitializerErrors. |
| private static Constructor getOptDataExceptionCtor() { |
| |
| try { |
| |
| Constructor result = |
| |
| (Constructor) AccessController.doPrivileged( |
| new PrivilegedExceptionAction() { |
| public java.lang.Object run() |
| throws NoSuchMethodException, |
| SecurityException { |
| |
| Constructor boolCtor |
| = OptionalDataException.class.getDeclaredConstructor( |
| new Class[] { |
| Boolean.TYPE }); |
| |
| boolCtor.setAccessible(true); |
| |
| return boolCtor; |
| }}); |
| |
| if (result == null) |
| // XXX I18N, logging needed. |
| throw new Error("Unable to find OptionalDataException constructor"); |
| |
| return result; |
| |
| } catch (Exception ex) { |
| // XXX I18N, logging needed. |
| throw new ExceptionInInitializerError(ex); |
| } |
| } |
| |
| // Create a new OptionalDataException with the EOF marker |
| // set to true. See handleOptionalDataMarshalException. |
| private OptionalDataException createOptionalDataException() { |
| try { |
| OptionalDataException result |
| = (OptionalDataException) |
| OPT_DATA_EXCEPTION_CTOR.newInstance(new Object[] { |
| Boolean.TRUE }); |
| |
| if (result == null) |
| // XXX I18N, logging needed. |
| throw new Error("Created null OptionalDataException"); |
| |
| return result; |
| |
| } catch (Exception ex) { |
| // XXX I18N, logging needed. |
| throw new Error("Couldn't create OptionalDataException", ex); |
| } |
| } |
| |
| // Return the stream format version currently being used |
| // to deserialize an object |
| protected byte getStreamFormatVersion() { |
| return streamFormatVersion; |
| } |
| |
| // At the beginning of data sent by a writeObject or |
| // writeExternal method there is a byte telling the |
| // reader the stream format version. |
| private void readFormatVersion() throws IOException { |
| |
| streamFormatVersion = orbStream.read_octet(); |
| |
| if (streamFormatVersion < 1 || |
| streamFormatVersion > vhandler.getMaximumStreamFormatVersion()) { |
| SystemException sysex = omgWrapper.unsupportedFormatVersion( |
| CompletionStatus.COMPLETED_MAYBE); |
| // XXX I18N? Logging for IOException? |
| IOException result = new IOException("Unsupported format version: " |
| + streamFormatVersion); |
| result.initCause( sysex ) ; |
| throw result ; |
| } |
| |
| if (streamFormatVersion == 2) { |
| if (!(orbStream instanceof ValueInputStream)) { |
| SystemException sysex = omgWrapper.notAValueinputstream( |
| CompletionStatus.COMPLETED_MAYBE); |
| // XXX I18N? Logging for IOException? |
| IOException result = new IOException("Not a ValueInputStream"); |
| result.initCause( sysex ) ; |
| throw result; |
| } |
| } |
| } |
| |
| public static void setTestFVDFlag(boolean val){ |
| // useFVDOnly = val; |
| } |
| |
| /** |
| * Dummy constructor; passes upper stream a dummy stream; |
| **/ |
| public IIOPInputStream() |
| throws java.io.IOException { |
| super(); |
| resetStream(); |
| } |
| |
| final void setOrbStream(org.omg.CORBA_2_3.portable.InputStream os) { |
| orbStream = os; |
| } |
| |
| final org.omg.CORBA_2_3.portable.InputStream getOrbStream() { |
| return orbStream; |
| } |
| |
| //added setSender and getSender |
| public final void setSender(CodeBase cb) { |
| cbSender = cb; |
| } |
| |
| public final CodeBase getSender() { |
| return cbSender; |
| } |
| |
| // 4365188 this is added to enable backward compatability w/ wrong |
| // rep-ids |
| public final void setValueHandler(ValueHandler vh) { |
| vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh; |
| } |
| |
| public final ValueHandler getValueHandler() { |
| return (javax.rmi.CORBA.ValueHandler) vhandler; |
| } |
| |
| final void increaseRecursionDepth(){ |
| recursionDepth++; |
| } |
| |
| final int decreaseRecursionDepth(){ |
| return --recursionDepth; |
| } |
| |
| /** |
| * Override the actions of the final method "readObject()" |
| * in ObjectInputStream. |
| * @since JDK1.1.6 |
| * |
| * Read an object from the ObjectInputStream. |
| * The class of the object, the signature of the class, and the values |
| * of the non-transient and non-static fields of the class and all |
| * of its supertypes are read. Default deserializing for a class can be |
| * overriden using the writeObject and readObject methods. |
| * Objects referenced by this object are read transitively so |
| * that a complete equivalent graph of objects is reconstructed by readObject. <p> |
| * |
| * The root object is completly restored when all of its fields |
| * and the objects it references are completely restored. At this |
| * point the object validation callbacks are executed in order |
| * based on their registered priorities. The callbacks are |
| * registered by objects (in the readObject special methods) |
| * as they are individually restored. |
| * |
| * Exceptions are thrown for problems with the InputStream and for classes |
| * that should not be deserialized. All exceptions are fatal to the |
| * InputStream and leave it in an indeterminate state; it is up to the caller |
| * to ignore or recover the stream state. |
| * @exception java.lang.ClassNotFoundException Class of a serialized object |
| * cannot be found. |
| * @exception InvalidClassException Something is wrong with a class used by |
| * serialization. |
| * @exception StreamCorruptedException Control information in the |
| * stream is inconsistent. |
| * @exception OptionalDataException Primitive data was found in the |
| * stream instead of objects. |
| * @exception IOException Any of the usual Input/Output related exceptions. |
| * @since JDK1.1 |
| */ |
| public final Object readObjectDelegate() throws IOException |
| { |
| try { |
| |
| readObjectState.readData(this); |
| |
| return orbStream.read_abstract_interface(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, true); |
| throw marshalException; |
| } catch(IndirectionException cdrie) |
| { |
| // The CDR stream had never seen the given offset before, |
| // so check the recursion manager (it will throw an |
| // IOException if it doesn't have a reference, either). |
| return activeRecursionMgr.getObject(cdrie.offset); |
| } |
| } |
| |
| final Object simpleReadObject(Class clz, |
| String repositoryID, |
| com.sun.org.omg.SendingContext.CodeBase sender, |
| int offset) |
| /* throws OptionalDataException, ClassNotFoundException, IOException */ |
| { |
| |
| /* Save the current state and get ready to read an object. */ |
| Object prevObject = currentObject; |
| ObjectStreamClass prevClassDesc = currentClassDesc; |
| Class prevClass = currentClass; |
| byte oldStreamFormatVersion = streamFormatVersion; |
| |
| simpleReadDepth++; // Entering |
| Object obj = null; |
| |
| /* |
| * Check for reset, handle it before reading an object. |
| */ |
| try { |
| // d4365188: backward compatability |
| if (vhandler.useFullValueDescription(clz, repositoryID)) { |
| obj = inputObjectUsingFVD(clz, repositoryID, sender, offset); |
| } else { |
| obj = inputObject(clz, repositoryID, sender, offset); |
| } |
| |
| obj = currentClassDesc.readResolve(obj); |
| } |
| catch(ClassNotFoundException cnfe) |
| { |
| bridge.throwException( cnfe ) ; |
| return null; |
| } |
| catch(IOException ioe) |
| { |
| // System.out.println("CLZ = " + clz + "; " + ioe.toString()); |
| bridge.throwException(ioe) ; |
| return null; |
| } |
| finally { |
| simpleReadDepth --; |
| currentObject = prevObject; |
| currentClassDesc = prevClassDesc; |
| currentClass = prevClass; |
| streamFormatVersion = oldStreamFormatVersion; |
| } |
| |
| |
| /* Check for thrown exceptions and re-throw them, clearing them if |
| * this is the last recursive call . |
| */ |
| IOException exIOE = abortIOException; |
| if (simpleReadDepth == 0) |
| abortIOException = null; |
| if (exIOE != null){ |
| bridge.throwException( exIOE ) ; |
| return null; |
| } |
| |
| |
| ClassNotFoundException exCNF = abortClassNotFoundException; |
| if (simpleReadDepth == 0) |
| abortClassNotFoundException = null; |
| if (exCNF != null) { |
| bridge.throwException( exCNF ) ; |
| return null; |
| } |
| |
| return obj; |
| } |
| |
| public final void simpleSkipObject(String repositoryID, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| /* throws OptionalDataException, ClassNotFoundException, IOException */ |
| { |
| |
| /* Save the current state and get ready to read an object. */ |
| Object prevObject = currentObject; |
| ObjectStreamClass prevClassDesc = currentClassDesc; |
| Class prevClass = currentClass; |
| byte oldStreamFormatVersion = streamFormatVersion; |
| |
| simpleReadDepth++; // Entering |
| Object obj = null; |
| |
| /* |
| * Check for reset, handle it before reading an object. |
| */ |
| try { |
| skipObjectUsingFVD(repositoryID, sender); |
| } |
| catch(ClassNotFoundException cnfe) |
| { |
| bridge.throwException( cnfe ) ; |
| return; |
| } |
| catch(IOException ioe) |
| { |
| bridge.throwException( ioe ) ; |
| return; |
| } |
| finally { |
| simpleReadDepth --; |
| streamFormatVersion = oldStreamFormatVersion; |
| currentObject = prevObject; |
| currentClassDesc = prevClassDesc; |
| currentClass = prevClass; |
| } |
| |
| |
| /* Check for thrown exceptions and re-throw them, clearing them if |
| * this is the last recursive call . |
| */ |
| IOException exIOE = abortIOException; |
| if (simpleReadDepth == 0) |
| abortIOException = null; |
| if (exIOE != null){ |
| bridge.throwException( exIOE ) ; |
| return; |
| } |
| |
| |
| ClassNotFoundException exCNF = abortClassNotFoundException; |
| if (simpleReadDepth == 0) |
| abortClassNotFoundException = null; |
| if (exCNF != null) { |
| bridge.throwException( exCNF ) ; |
| return; |
| } |
| |
| return; |
| } |
| ///////////////// |
| |
| /** |
| * This method is called by trusted subclasses of ObjectOutputStream |
| * that constructed ObjectOutputStream using the |
| * protected no-arg constructor. The subclass is expected to provide |
| * an override method with the modifier "final". |
| * |
| * @return the Object read from the stream. |
| * |
| * @see #ObjectInputStream() |
| * @see #readObject |
| * @since JDK 1.2 |
| */ |
| protected final Object readObjectOverride() |
| throws OptionalDataException, ClassNotFoundException, IOException |
| { |
| return readObjectDelegate(); |
| } |
| |
| /** |
| * Override the actions of the final method "defaultReadObject()" |
| * in ObjectInputStream. |
| * @since JDK1.1.6 |
| * |
| * Read the non-static and non-transient fields of the current class |
| * from this stream. This may only be called from the readObject method |
| * of the class being deserialized. It will throw the NotActiveException |
| * if it is called otherwise. |
| * |
| * @exception java.lang.ClassNotFoundException if the class of a serialized |
| * object could not be found. |
| * @exception IOException if an I/O error occurs. |
| * @exception NotActiveException if the stream is not currently reading |
| * objects. |
| * @since JDK1.1 |
| */ |
| public final void defaultReadObjectDelegate() |
| /* throws IOException, ClassNotFoundException, NotActiveException */ |
| { |
| try { |
| if (currentObject == null || currentClassDesc == null) |
| // XXX I18N, logging needed. |
| throw new NotActiveException("defaultReadObjectDelegate"); |
| |
| // The array will be null unless fields were retrieved |
| // remotely because of a serializable version difference. |
| // Bug fix for 4365188. See the definition of |
| // defaultReadObjectFVDMembers for more information. |
| if (defaultReadObjectFVDMembers != null && |
| defaultReadObjectFVDMembers.length > 0) { |
| |
| // WARNING: Be very careful! What if some of |
| // these fields actually have to do this, too? |
| // This works because the defaultReadObjectFVDMembers |
| // reference is passed to inputClassFields, but |
| // there is no guarantee that |
| // defaultReadObjectFVDMembers will point to the |
| // same array after calling inputClassFields. |
| |
| // Use the remote fields to unmarshal. |
| inputClassFields(currentObject, |
| currentClass, |
| currentClassDesc, |
| defaultReadObjectFVDMembers, |
| cbSender); |
| |
| } else { |
| |
| // Use the local fields to unmarshal. |
| ObjectStreamField[] fields = |
| currentClassDesc.getFieldsNoCopy(); |
| if (fields.length > 0) { |
| inputClassFields(currentObject, currentClass, fields, cbSender); |
| } |
| } |
| } |
| catch(NotActiveException nae) |
| { |
| bridge.throwException( nae ) ; |
| } |
| catch(IOException ioe) |
| { |
| bridge.throwException( ioe ) ; |
| } |
| catch(ClassNotFoundException cnfe) |
| { |
| bridge.throwException( cnfe ) ; |
| } |
| |
| } |
| |
| /** |
| * Override the actions of the final method "enableResolveObject()" |
| * in ObjectInputStream. |
| * @since JDK1.1.6 |
| * |
| * Enable the stream to allow objects read from the stream to be replaced. |
| * If the stream is a trusted class it is allowed to enable replacment. |
| * Trusted classes are those classes with a classLoader equals null. <p> |
| * |
| * When enabled the resolveObject method is called for every object |
| * being deserialized. |
| * |
| * @exception SecurityException The classloader of this stream object is non-null. |
| * @since JDK1.1 |
| */ |
| public final boolean enableResolveObjectDelegate(boolean enable) |
| /* throws SecurityException */ |
| { |
| return false; |
| } |
| |
| // The following three methods allow the implementing orbStream |
| // to provide mark/reset behavior as defined in java.io.InputStream. |
| |
| public final void mark(int readAheadLimit) { |
| orbStream.mark(readAheadLimit); |
| } |
| |
| public final boolean markSupported() { |
| return orbStream.markSupported(); |
| } |
| |
| public final void reset() throws IOException { |
| try { |
| orbStream.reset(); |
| } catch (Error e) { |
| IOException err = new IOException(e.getMessage()); |
| err.initCause(e) ; |
| throw err ; |
| } |
| } |
| |
| public final int available() throws IOException{ |
| return 0; // unreliable |
| } |
| |
| public final void close() throws IOException{ |
| // no op |
| } |
| |
| public final int read() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return (orbStream.read_octet() << 0) & 0x000000FF; |
| } catch (MARSHAL marshalException) { |
| if (marshalException.minor |
| == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) { |
| setState(IN_READ_OBJECT_NO_MORE_OPT_DATA); |
| return -1; |
| } |
| |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e) ; |
| throw exc ; |
| } |
| } |
| |
| public final int read(byte data[], int offset, int length) throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| orbStream.read_octet_array(data, offset, length); |
| return length; |
| } catch (MARSHAL marshalException) { |
| if (marshalException.minor |
| == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) { |
| setState(IN_READ_OBJECT_NO_MORE_OPT_DATA); |
| return -1; |
| } |
| |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e) ; |
| throw exc ; |
| } |
| |
| } |
| |
| public final boolean readBoolean() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_boolean(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final byte readByte() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_octet(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final char readChar() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_wchar(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final double readDouble() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_double(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final float readFloat() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_float(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final void readFully(byte data[]) throws IOException{ |
| // d11623 : implement readFully, required for serializing some core classes |
| |
| readFully(data, 0, data.length); |
| } |
| |
| public final void readFully(byte data[], int offset, int size) throws IOException{ |
| // d11623 : implement readFully, required for serializing some core classes |
| try{ |
| readObjectState.readData(this); |
| |
| orbStream.read_octet_array(data, offset, size); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final int readInt() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_long(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final String readLine() throws IOException{ |
| // XXX I18N, logging needed. |
| throw new IOException("Method readLine not supported"); |
| } |
| |
| public final long readLong() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_longlong(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final short readShort() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return orbStream.read_short(); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| protected final void readStreamHeader() throws IOException, StreamCorruptedException{ |
| // no op |
| } |
| |
| public final int readUnsignedByte() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return (orbStream.read_octet() << 0) & 0x000000FF; |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| public final int readUnsignedShort() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return (orbStream.read_ushort() << 0) & 0x0000FFFF; |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| /** |
| * Helper method for correcting the Kestrel bug 4367783 (dealing |
| * with larger than 8-bit chars). The old behavior is preserved |
| * in orbutil.IIOPInputStream_1_3 in order to interoperate with |
| * our legacy ORBs. |
| */ |
| protected String internalReadUTF(org.omg.CORBA.portable.InputStream stream) |
| { |
| return stream.read_wstring(); |
| } |
| |
| public final String readUTF() throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| return internalReadUTF(orbStream); |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e); |
| throw exc ; |
| } |
| } |
| |
| // If the ORB stream detects an incompatibility between what's |
| // on the wire and what our Serializable's readObject wants, |
| // it throws a MARSHAL exception with a specific minor code. |
| // This is rethrown to the readObject as an OptionalDataException. |
| // So far in RMI-IIOP, this process isn't specific enough to |
| // tell the readObject how much data is available, so we always |
| // set the OptionalDataException's EOF marker to true. |
| private void handleOptionalDataMarshalException(MARSHAL marshalException, |
| boolean objectRead) |
| throws IOException { |
| |
| // Java Object Serialization spec 3.4: "If the readObject method |
| // of the class attempts to read more data than is present in the |
| // optional part of the stream for this class, the stream will |
| // return -1 for bytewise reads, throw an EOFException for |
| // primitive data reads, or throw an OptionalDataException |
| // with the eof field set to true for object reads." |
| if (marshalException.minor |
| == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) { |
| |
| IOException result; |
| |
| if (!objectRead) |
| result = new EOFException("No more optional data"); |
| else |
| result = createOptionalDataException(); |
| |
| result.initCause(marshalException); |
| |
| setState(IN_READ_OBJECT_NO_MORE_OPT_DATA); |
| |
| throw result; |
| } |
| } |
| |
| public final synchronized void registerValidation(ObjectInputValidation obj, |
| int prio) |
| throws NotActiveException, InvalidObjectException{ |
| // XXX I18N, logging needed. |
| throw new Error("Method registerValidation not supported"); |
| } |
| |
| protected final Class resolveClass(ObjectStreamClass v) |
| throws IOException, ClassNotFoundException{ |
| // XXX I18N, logging needed. |
| throw new IOException("Method resolveClass not supported"); |
| } |
| |
| protected final Object resolveObject(Object obj) throws IOException{ |
| // XXX I18N, logging needed. |
| throw new IOException("Method resolveObject not supported"); |
| } |
| |
| public final int skipBytes(int len) throws IOException{ |
| try{ |
| readObjectState.readData(this); |
| |
| byte buf[] = new byte[len]; |
| orbStream.read_octet_array(buf, 0, len); |
| return len; |
| } catch (MARSHAL marshalException) { |
| handleOptionalDataMarshalException(marshalException, false); |
| |
| throw marshalException; |
| } catch(Error e) { |
| IOException exc = new IOException(e.getMessage()); |
| exc.initCause(e) ; |
| throw exc ; |
| } |
| } |
| |
| private Object inputObject(Class clz, |
| String repositoryID, |
| com.sun.org.omg.SendingContext.CodeBase sender, |
| int offset) |
| throws IOException, ClassNotFoundException |
| { |
| |
| /* |
| * Get the descriptor and then class of the incoming object. |
| */ |
| |
| currentClassDesc = ObjectStreamClass.lookup(clz); |
| currentClass = currentClassDesc.forClass(); |
| //currentClassDesc.setClass(currentClass); |
| if (currentClass == null) |
| // XXX I18N, logging needed. |
| throw new ClassNotFoundException(currentClassDesc.getName()); |
| |
| try { |
| /* If Externalizable, |
| * Create an instance and tell it to read its data. |
| * else, |
| * Handle it as a serializable class. |
| */ |
| if (Enum.class.isAssignableFrom( clz )) { |
| int ordinal = orbStream.read_long() ; |
| String value = (String)orbStream.read_value( String.class ) ; |
| return Enum.valueOf( clz, value ) ; |
| } else if (currentClassDesc.isExternalizable()) { |
| try { |
| currentObject = (currentClass == null) ? |
| null : currentClassDesc.newInstance(); |
| if (currentObject != null) { |
| |
| // Store this object and its beginning position |
| // since there might be indirections to it while |
| // it's been unmarshalled. |
| activeRecursionMgr.addObject(offset, currentObject); |
| |
| // Read format version |
| readFormatVersion(); |
| |
| Externalizable ext = (Externalizable)currentObject; |
| ext.readExternal(this); |
| } |
| } catch (InvocationTargetException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InvocationTargetException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (UnsupportedOperationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "UnsupportedOperationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (InstantiationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InstantiationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } |
| } // end : if (currentClassDesc.isExternalizable()) |
| else { |
| /* Count number of classes and descriptors we might have |
| * to work on. |
| */ |
| |
| ObjectStreamClass currdesc = currentClassDesc; |
| Class currclass = currentClass; |
| |
| int spBase = spClass; // current top of stack |
| |
| /* The object's classes should be processed from supertype to subtype |
| * Push all the clases of the current object onto a stack. |
| * Note that only the serializable classes are represented |
| * in the descriptor list. |
| * |
| * Handle versioning where one or more supertypes of |
| * have been inserted or removed. The stack will |
| * contain pairs of descriptors and the corresponding |
| * class. If the object has a class that did not occur in |
| * the original the descriptor will be null. If the |
| * original object had a descriptor for a class not |
| * present in the local hierarchy of the object the class will be |
| * null. |
| * |
| */ |
| |
| /* |
| * This is your basic diff pattern, made simpler |
| * because reordering is not allowed. |
| */ |
| // sun.4296963 ibm.11861 |
| // d11861 we should stop when we find the highest serializable class |
| // We need this so that when we allocate the new object below, we |
| // can call the constructor of the non-serializable superclass. |
| // Note that in the JRMP variant of this code the |
| // ObjectStreamClass.lookup() method handles this, but we've put |
| // this fix here rather than change lookup because the new behaviour |
| // is needed in other cases. |
| |
| for (currdesc = currentClassDesc, currclass = currentClass; |
| currdesc != null && currdesc.isSerializable(); /*sun.4296963 ibm.11861*/ |
| currdesc = currdesc.getSuperclass()) { |
| |
| /* |
| * Search the classes to see if the class of this |
| * descriptor appears further up the hierarchy. Until |
| * it's found assume its an inserted class. If it's |
| * not found, its the descriptor's class that has been |
| * removed. |
| */ |
| Class cc = currdesc.forClass(); |
| Class cl; |
| for (cl = currclass; cl != null; cl = cl.getSuperclass()) { |
| if (cc == cl) { |
| // found a superclass that matches this descriptor |
| break; |
| } else { |
| /* Ignore a class that doesn't match. No |
| * action is needed since it is already |
| * initialized. |
| */ |
| } |
| } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass()) |
| /* Test if there is room for this new entry. |
| * If not, double the size of the arrays and copy the contents. |
| */ |
| spClass++; |
| if (spClass >= classes.length) { |
| int newlen = classes.length * 2; |
| Class[] newclasses = new Class[newlen]; |
| ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen]; |
| |
| System.arraycopy(classes, 0, |
| newclasses, 0, |
| classes.length); |
| System.arraycopy(classdesc, 0, |
| newclassdesc, 0, |
| classes.length); |
| |
| classes = newclasses; |
| classdesc = newclassdesc; |
| } |
| |
| if (cl == null) { |
| /* Class not found corresponding to this descriptor. |
| * Pop off all the extra classes pushed. |
| * Push the descriptor and a null class. |
| */ |
| classdesc[spClass] = currdesc; |
| classes[spClass] = null; |
| } else { |
| /* Current class descriptor matches current class. |
| * Some classes may have been inserted. |
| * Record the match and advance the class, continue |
| * with the next descriptor. |
| */ |
| classdesc[spClass] = currdesc; |
| classes[spClass] = cl; |
| currclass = cl.getSuperclass(); |
| } |
| } // end : for (currdesc = currentClassDesc, currclass = currentClass; |
| |
| /* Allocate a new object. The object is only constructed |
| * above the highest serializable class and is set to |
| * default values for all more specialized classes. |
| */ |
| try { |
| currentObject = (currentClass == null) ? |
| null : currentClassDesc.newInstance() ; |
| |
| // Store this object and its beginning position |
| // since there might be indirections to it while |
| // it's been unmarshalled. |
| activeRecursionMgr.addObject(offset, currentObject); |
| } catch (InvocationTargetException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InvocationTargetException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (UnsupportedOperationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "UnsupportedOperationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (InstantiationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InstantiationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } |
| |
| /* |
| * For all the pushed descriptors and classes. |
| * if the class has its own writeObject and readObject methods |
| * call the readObject method |
| * else |
| * invoke the defaultReadObject method |
| */ |
| try { |
| for (spClass = spClass; spClass > spBase; spClass--) { |
| /* |
| * Set current descriptor and corresponding class |
| */ |
| currentClassDesc = classdesc[spClass]; |
| currentClass = classes[spClass]; |
| if (classes[spClass] != null) { |
| /* Read the data from the stream described by the |
| * descriptor and store into the matching class. |
| */ |
| |
| ReadObjectState oldState = readObjectState; |
| setState(DEFAULT_STATE); |
| |
| try { |
| |
| // Changed since invokeObjectReader no longer does this. |
| if (currentClassDesc.hasWriteObject()) { |
| |
| // Read format version |
| readFormatVersion(); |
| |
| // Read defaultWriteObject indicator |
| boolean calledDefaultWriteObject = readBoolean(); |
| |
| readObjectState.beginUnmarshalCustomValue(this, |
| calledDefaultWriteObject, |
| (currentClassDesc.readObjectMethod |
| != null)); |
| } else { |
| if (currentClassDesc.hasReadObject()) |
| setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED); |
| } |
| |
| if (!invokeObjectReader(currentClassDesc, currentObject, currentClass) || |
| readObjectState == IN_READ_OBJECT_DEFAULTS_SENT) { |
| |
| // Error case of no readObject and didn't call |
| // defaultWriteObject handled in default state |
| |
| ObjectStreamField[] fields = |
| currentClassDesc.getFieldsNoCopy(); |
| if (fields.length > 0) { |
| inputClassFields(currentObject, currentClass, fields, sender); |
| } |
| } |
| |
| if (currentClassDesc.hasWriteObject()) |
| readObjectState.endUnmarshalCustomValue(this); |
| |
| } finally { |
| setState(oldState); |
| } |
| |
| } else { |
| |
| // _REVISIT_ : Can we ever get here? |
| /* No local class for this descriptor, |
| * Skip over the data for this class. |
| * like defaultReadObject with a null currentObject. |
| * The code will read the values but discard them. |
| */ |
| ObjectStreamField[] fields = |
| currentClassDesc.getFieldsNoCopy(); |
| if (fields.length > 0) { |
| inputClassFields(null, currentClass, fields, sender); |
| } |
| |
| } |
| |
| } |
| } finally { |
| // Make sure we exit at the same stack level as when we started. |
| spClass = spBase; |
| } |
| } |
| } finally { |
| // We've completed deserializing this object. Any |
| // future indirections will be handled correctly at the |
| // CDR level. The ActiveRecursionManager only deals with |
| // objects currently being deserialized. |
| activeRecursionMgr.removeObject(offset); |
| } |
| |
| return currentObject; |
| } |
| |
| // This retrieves a vector of FVD's for the hierarchy of serializable classes stemming from |
| // repositoryID. It is assumed that the sender will not provide base_value id's for non-serializable |
| // classes! |
| private Vector getOrderedDescriptions(String repositoryID, |
| com.sun.org.omg.SendingContext.CodeBase sender) { |
| Vector descs = new Vector(); |
| |
| if (sender == null) { |
| return descs; |
| } |
| |
| FullValueDescription aFVD = sender.meta(repositoryID); |
| while (aFVD != null) { |
| descs.insertElementAt(aFVD, 0); |
| if ((aFVD.base_value != null) && !kEmptyStr.equals(aFVD.base_value)) { |
| aFVD = sender.meta(aFVD.base_value); |
| } |
| else return descs; |
| } |
| |
| return descs; |
| } |
| |
| /** |
| * This input method uses FullValueDescriptions retrieved from the sender's runtime to |
| * read in the data. This method is capable of throwing out data not applicable to client's fields. |
| * This method handles instances where the reader has a class not sent by the sender, the sender sent |
| * a class not present on the reader, and/or the reader's class does not match the sender's class. |
| * |
| * NOTE : If the local description indicates custom marshaling and the remote type's FVD also |
| * indicates custom marsahling than the local type is used to read the data off the wire. However, |
| * if either says custom while the other does not, a MARSHAL error is thrown. Externalizable is |
| * a form of custom marshaling. |
| * |
| */ |
| private Object inputObjectUsingFVD(Class clz, |
| String repositoryID, |
| com.sun.org.omg.SendingContext.CodeBase sender, |
| int offset) |
| throws IOException, ClassNotFoundException |
| { |
| int spBase = spClass; // current top of stack |
| try{ |
| |
| /* |
| * Get the descriptor and then class of the incoming object. |
| */ |
| |
| ObjectStreamClass currdesc = currentClassDesc = ObjectStreamClass.lookup(clz); |
| Class currclass = currentClass = clz; |
| |
| /* If Externalizable, |
| * Create an instance and tell it to read its data. |
| * else, |
| * Handle it as a serializable class. |
| */ |
| if (currentClassDesc.isExternalizable()) { |
| try { |
| currentObject = (currentClass == null) ? |
| null : currentClassDesc.newInstance(); |
| if (currentObject != null) { |
| // Store this object and its beginning position |
| // since there might be indirections to it while |
| // it's been unmarshalled. |
| activeRecursionMgr.addObject(offset, currentObject); |
| |
| // Read format version |
| readFormatVersion(); |
| |
| Externalizable ext = (Externalizable)currentObject; |
| ext.readExternal(this); |
| } |
| } catch (InvocationTargetException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InvocationTargetException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (UnsupportedOperationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "UnsupportedOperationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (InstantiationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InstantiationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } |
| } else { |
| /* |
| * This is your basic diff pattern, made simpler |
| * because reordering is not allowed. |
| */ |
| for (currdesc = currentClassDesc, currclass = currentClass; |
| currdesc != null && currdesc.isSerializable(); /*sun.4296963 ibm.11861*/ |
| |
| currdesc = currdesc.getSuperclass()) { |
| |
| /* |
| * Search the classes to see if the class of this |
| * descriptor appears further up the hierarchy. Until |
| * it's found assume its an inserted class. If it's |
| * not found, its the descriptor's class that has been |
| * removed. |
| */ |
| Class cc = currdesc.forClass(); |
| Class cl; |
| for (cl = currclass; cl != null; cl = cl.getSuperclass()) { |
| if (cc == cl) { |
| // found a superclass that matches this descriptor |
| break; |
| } else { |
| /* Ignore a class that doesn't match. No |
| * action is needed since it is already |
| * initialized. |
| */ |
| } |
| } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass()) |
| /* Test if there is room for this new entry. |
| * If not, double the size of the arrays and copy the contents. |
| */ |
| spClass++; |
| if (spClass >= classes.length) { |
| int newlen = classes.length * 2; |
| Class[] newclasses = new Class[newlen]; |
| ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen]; |
| |
| System.arraycopy(classes, 0, |
| newclasses, 0, |
| classes.length); |
| System.arraycopy(classdesc, 0, |
| newclassdesc, 0, |
| classes.length); |
| |
| classes = newclasses; |
| classdesc = newclassdesc; |
| } |
| |
| if (cl == null) { |
| /* Class not found corresponding to this descriptor. |
| * Pop off all the extra classes pushed. |
| * Push the descriptor and a null class. |
| */ |
| classdesc[spClass] = currdesc; |
| classes[spClass] = null; |
| } else { |
| /* Current class descriptor matches current class. |
| * Some classes may have been inserted. |
| * Record the match and advance the class, continue |
| * with the next descriptor. |
| */ |
| classdesc[spClass] = currdesc; |
| classes[spClass] = cl; |
| currclass = cl.getSuperclass(); |
| } |
| } // end : for (currdesc = currentClassDesc, currclass = currentClass; |
| |
| /* Allocate a new object. |
| */ |
| try { |
| currentObject = (currentClass == null) ? |
| null : currentClassDesc.newInstance(); |
| |
| // Store this object and its beginning position |
| // since there might be indirections to it while |
| // it's been unmarshalled. |
| activeRecursionMgr.addObject(offset, currentObject); |
| } catch (InvocationTargetException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InvocationTargetException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (UnsupportedOperationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "UnsupportedOperationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } catch (InstantiationException e) { |
| InvalidClassException exc = new InvalidClassException( |
| currentClass.getName(), |
| "InstantiationException accessing no-arg constructor"); |
| exc.initCause( e ) ; |
| throw exc ; |
| } |
| |
| Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements(); |
| |
| while((fvdsList.hasMoreElements()) && (spClass > spBase)) { |
| FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement(); |
| // d4365188: backward compatability |
| String repIDForFVD = vhandler.getClassName(fvd.id); |
| String repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass)); |
| |
| while ((spClass > spBase) && |
| (!repIDForFVD.equals(repIDForClass))) { |
| int pos = findNextClass(repIDForFVD, classes, spClass, spBase); |
| if (pos != -1) { |
| spClass = pos; |
| currclass = currentClass = classes[spClass]; |
| repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass)); |
| } |
| else { // Read and throw away one level of the fvdslist |
| |
| // This seems to mean that the sender had a superclass that |
| // we don't have |
| |
| if (fvd.is_custom) { |
| |
| readFormatVersion(); |
| boolean calledDefaultWriteObject = readBoolean(); |
| |
| if (calledDefaultWriteObject) |
| inputClassFields(null, null, null, fvd.members, sender); |
| |
| if (getStreamFormatVersion() == 2) { |
| |
| ((ValueInputStream)getOrbStream()).start_value(); |
| ((ValueInputStream)getOrbStream()).end_value(); |
| } |
| |
| // WARNING: If stream format version is 1 and there's |
| // optional data, we'll get some form of exception down |
| // the line or data corruption. |
| |
| } else { |
| |
| inputClassFields(null, currentClass, null, fvd.members, sender); |
| } |
| |
| if (fvdsList.hasMoreElements()){ |
| fvd = (FullValueDescription)fvdsList.nextElement(); |
| repIDForFVD = vhandler.getClassName(fvd.id); |
| } |
| else return currentObject; |
| } |
| } |
| |
| currdesc = currentClassDesc = ObjectStreamClass.lookup(currentClass); |
| |
| if (!repIDForClass.equals("java.lang.Object")) { |
| |
| // If the sender used custom marshaling, then it should have put |
| // the two bytes on the wire indicating stream format version |
| // and whether or not the writeObject method called |
| // defaultWriteObject/writeFields. |
| |
| ReadObjectState oldState = readObjectState; |
| setState(DEFAULT_STATE); |
| |
| try { |
| |
| if (fvd.is_custom) { |
| |
| // Read format version |
| readFormatVersion(); |
| |
| // Read defaultWriteObject indicator |
| boolean calledDefaultWriteObject = readBoolean(); |
| |
| readObjectState.beginUnmarshalCustomValue(this, |
| calledDefaultWriteObject, |
| (currentClassDesc.readObjectMethod |
| != null)); |
| } |
| |
| boolean usedReadObject = false; |
| |
| // Always use readObject if it exists, and fall back to default |
| // unmarshaling if it doesn't. |
| try { |
| |
| if (!fvd.is_custom && currentClassDesc.hasReadObject()) |
| setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED); |
| |
| // See the definition of defaultReadObjectFVDMembers |
| // for more information. This concerns making sure |
| // we use the remote FVD's members in defaultReadObject. |
| defaultReadObjectFVDMembers = fvd.members; |
| usedReadObject = invokeObjectReader(currentClassDesc, |
| currentObject, |
| currentClass); |
| |
| } finally { |
| defaultReadObjectFVDMembers = null; |
| } |
| |
| // Note that the !usedReadObject !calledDefaultWriteObject |
| // case is handled by the beginUnmarshalCustomValue method |
| // of the default state |
| if (!usedReadObject || readObjectState == IN_READ_OBJECT_DEFAULTS_SENT) |
| inputClassFields(currentObject, currentClass, currdesc, fvd.members, sender); |
| |
| if (fvd.is_custom) |
| readObjectState.endUnmarshalCustomValue(this); |
| |
| } finally { |
| setState(oldState); |
| } |
| |
| currclass = currentClass = classes[--spClass]; |
| |
| } else { |
| |
| // The remaining hierarchy of the local class does not match the sender's FVD. |
| // So, use remaining FVDs to read data off wire. If any remaining FVDs indicate |
| // custom marshaling, throw MARSHAL error. |
| inputClassFields(null, currentClass, null, fvd.members, sender); |
| |
| while (fvdsList.hasMoreElements()){ |
| fvd = (FullValueDescription)fvdsList.nextElement(); |
| |
| if (fvd.is_custom) |
| skipCustomUsingFVD(fvd.members, sender); |
| else |
| inputClassFields(null, currentClass, null, fvd.members, sender); |
| } |
| |
| } |
| |
| } // end : while(fvdsList.hasMoreElements()) |
| while (fvdsList.hasMoreElements()){ |
| |
| FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement(); |
| if (fvd.is_custom) |
| skipCustomUsingFVD(fvd.members, sender); |
| else |
| throwAwayData(fvd.members, sender); |
| } |
| } |
| |
| return currentObject; |
| } |
| finally { |
| // Make sure we exit at the same stack level as when we started. |
| spClass = spBase; |
| |
| // We've completed deserializing this object. Any |
| // future indirections will be handled correctly at the |
| // CDR level. The ActiveRecursionManager only deals with |
| // objects currently being deserialized. |
| activeRecursionMgr.removeObject(offset); |
| } |
| |
| } |
| |
| /** |
| * This input method uses FullValueDescriptions retrieved from the sender's runtime to |
| * read in the data. This method is capable of throwing out data not applicable to client's fields. |
| * |
| * NOTE : If the local description indicates custom marshaling and the remote type's FVD also |
| * indicates custom marsahling than the local type is used to read the data off the wire. However, |
| * if either says custom while the other does not, a MARSHAL error is thrown. Externalizable is |
| * a form of custom marshaling. |
| * |
| */ |
| private Object skipObjectUsingFVD(String repositoryID, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| throws IOException, ClassNotFoundException |
| { |
| |
| Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements(); |
| |
| while(fvdsList.hasMoreElements()) { |
| FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement(); |
| String repIDForFVD = vhandler.getClassName(fvd.id); |
| |
| if (!repIDForFVD.equals("java.lang.Object")) { |
| if (fvd.is_custom) { |
| |
| readFormatVersion(); |
| |
| boolean calledDefaultWriteObject = readBoolean(); |
| |
| if (calledDefaultWriteObject) |
| inputClassFields(null, null, null, fvd.members, sender); |
| |
| if (getStreamFormatVersion() == 2) { |
| |
| ((ValueInputStream)getOrbStream()).start_value(); |
| ((ValueInputStream)getOrbStream()).end_value(); |
| } |
| |
| // WARNING: If stream format version is 1 and there's |
| // optional data, we'll get some form of exception down |
| // the line. |
| |
| } else { |
| // Use default marshaling |
| inputClassFields(null, null, null, fvd.members, sender); |
| } |
| } |
| |
| } // end : while(fvdsList.hasMoreElements()) |
| return null; |
| |
| } |
| |
| /////////////////// |
| |
| private int findNextClass(String classname, Class classes[], int _spClass, int _spBase){ |
| |
| for (int i = _spClass; i > _spBase; i--){ |
| if (classname.equals(classes[i].getName())) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /* |
| * Invoke the readObject method if present. Assumes that in the case of custom |
| * marshaling, the format version and defaultWriteObject indicator were already |
| * removed. |
| */ |
| private boolean invokeObjectReader(ObjectStreamClass osc, Object obj, Class aclass) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException |
| { |
| if (osc.readObjectMethod == null) { |
| return false; |
| } |
| |
| try { |
| osc.readObjectMethod.invoke( obj, readObjectArgList ) ; |
| return true; |
| } catch (InvocationTargetException e) { |
| Throwable t = e.getTargetException(); |
| if (t instanceof ClassNotFoundException) |
| throw (ClassNotFoundException)t; |
| else if (t instanceof IOException) |
| throw (IOException)t; |
| else if (t instanceof RuntimeException) |
| throw (RuntimeException) t; |
| else if (t instanceof Error) |
| throw (Error) t; |
| else |
| // XXX I18N, logging needed. |
| throw new Error("internal error"); |
| } catch (IllegalAccessException e) { |
| return false; |
| } |
| } |
| |
| /* |
| * Reset the stream to be just like it was after the constructor. |
| */ |
| private void resetStream() throws IOException { |
| |
| if (classes == null) |
| classes = new Class[20]; |
| else { |
| for (int i = 0; i < classes.length; i++) |
| classes[i] = null; |
| } |
| if (classdesc == null) |
| classdesc = new ObjectStreamClass[20]; |
| else { |
| for (int i = 0; i < classdesc.length; i++) |
| classdesc[i] = null; |
| } |
| spClass = 0; |
| |
| if (callbacks != null) |
| callbacks.setSize(0); // discard any pending callbacks |
| } |
| |
| /** |
| * Factored out of inputClassFields This reads a primitive value and sets it |
| * in the field of o described by the ObjectStreamField field. |
| * |
| * Note that reflection cannot be used here, because reflection cannot be used |
| * to set final fields. |
| */ |
| private void inputPrimitiveField(Object o, Class cl, ObjectStreamField field) |
| throws InvalidClassException, IOException { |
| |
| try { |
| switch (field.getTypeCode()) { |
| case 'B': |
| byte byteValue = orbStream.read_octet(); |
| bridge.putByte( o, field.getFieldID(), byteValue ) ; |
| //reflective code: field.getField().setByte( o, byteValue ) ; |
| break; |
| case 'Z': |
| boolean booleanValue = orbStream.read_boolean(); |
| bridge.putBoolean( o, field.getFieldID(), booleanValue ) ; |
| //reflective code: field.getField().setBoolean( o, booleanValue ) ; |
| break; |
| case 'C': |
| char charValue = orbStream.read_wchar(); |
| bridge.putChar( o, field.getFieldID(), charValue ) ; |
| //reflective code: field.getField().setChar( o, charValue ) ; |
| break; |
| case 'S': |
| short shortValue = orbStream.read_short(); |
| bridge.putShort( o, field.getFieldID(), shortValue ) ; |
| //reflective code: field.getField().setShort( o, shortValue ) ; |
| break; |
| case 'I': |
| int intValue = orbStream.read_long(); |
| bridge.putInt( o, field.getFieldID(), intValue ) ; |
| //reflective code: field.getField().setInt( o, intValue ) ; |
| break; |
| case 'J': |
| long longValue = orbStream.read_longlong(); |
| bridge.putLong( o, field.getFieldID(), longValue ) ; |
| //reflective code: field.getField().setLong( o, longValue ) ; |
| break; |
| case 'F' : |
| float floatValue = orbStream.read_float(); |
| bridge.putFloat( o, field.getFieldID(), floatValue ) ; |
| //reflective code: field.getField().setFloat( o, floatValue ) ; |
| break; |
| case 'D' : |
| double doubleValue = orbStream.read_double(); |
| bridge.putDouble( o, field.getFieldID(), doubleValue ) ; |
| //reflective code: field.getField().setDouble( o, doubleValue ) ; |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new InvalidClassException(cl.getName()); |
| } |
| } catch (IllegalArgumentException e) { |
| /* This case should never happen. If the field types |
| are not the same, InvalidClassException is raised when |
| matching the local class to the serialized ObjectStreamClass. */ |
| ClassCastException cce = new ClassCastException("Assigning instance of class " + |
| field.getType().getName() + |
| " to field " + |
| currentClassDesc.getName() + '#' + |
| field.getField().getName()); |
| cce.initCause( e ) ; |
| throw cce ; |
| } |
| } |
| |
| private Object inputObjectField(org.omg.CORBA.ValueMember field, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| throws IndirectionException, ClassNotFoundException, IOException, |
| StreamCorruptedException { |
| |
| Object objectValue = null; |
| Class type = null; |
| String id = field.id; |
| |
| try { |
| type = vhandler.getClassFromType(id); |
| } catch(ClassNotFoundException cnfe) { |
| // Make sure type = null |
| type = null; |
| } |
| |
| String signature = null; |
| if (type != null) |
| signature = ValueUtility.getSignature(field); |
| |
| if (signature != null && (signature.equals("Ljava/lang/Object;") || |
| signature.equals("Ljava/io/Serializable;") || |
| signature.equals("Ljava/io/Externalizable;"))) { |
| objectValue = javax.rmi.CORBA.Util.readAny(orbStream); |
| } else { |
| // Decide what method call to make based on the type. If |
| // it is a type for which we need to load a stub, convert |
| // the type to the correct stub type. |
| // |
| // NOTE : Since FullValueDescription does not allow us |
| // to ask whether something is an interface we do not |
| // have the ability to optimize this check. |
| |
| int callType = ValueHandlerImpl.kValueType; |
| |
| if (!vhandler.isSequence(id)) { |
| |
| if (field.type.kind().value() == kRemoteTypeCode.kind().value()) { |
| |
| // RMI Object reference... |
| callType = ValueHandlerImpl.kRemoteType; |
| |
| } else { |
| |
| // REVISIT. If we don't have the local class, |
| // we should probably verify that it's an RMI type, |
| // query the remote FVD, and use is_abstract. |
| // Our FVD seems to get NullPointerExceptions for any |
| // non-RMI types. |
| |
| // This uses the local class in the same way as |
| // inputObjectField(ObjectStreamField) does. REVISIT |
| // inputObjectField(ObjectStreamField)'s loadStubClass |
| // logic. Assumption is that the given type cannot |
| // evolve to become a CORBA abstract interface or |
| // a RMI abstract interface. |
| |
| if (type != null && type.isInterface() && |
| (vhandler.isAbstractBase(type) || |
| ObjectStreamClassCorbaExt.isAbstractInterface(type))) { |
| |
| callType = ValueHandlerImpl.kAbstractType; |
| } |
| } |
| } |
| |
| // Now that we have used the FVD of the field to determine the proper course |
| // of action, it is ok to use the type (Class) from this point forward since |
| // the rep. id for this read will also follow on the wire. |
| |
| switch (callType) { |
| case ValueHandlerImpl.kRemoteType: |
| if (type != null) |
| objectValue = Utility.readObjectAndNarrow(orbStream, type); |
| else |
| objectValue = orbStream.read_Object(); |
| break; |
| case ValueHandlerImpl.kAbstractType: |
| if (type != null) |
| objectValue = Utility.readAbstractAndNarrow(orbStream, type); |
| else |
| objectValue = orbStream.read_abstract_interface(); |
| break; |
| case ValueHandlerImpl.kValueType: |
| if (type != null) |
| objectValue = orbStream.read_value(type); |
| else |
| objectValue = orbStream.read_value(); |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new StreamCorruptedException("Unknown callType: " + callType); |
| } |
| } |
| |
| return objectValue; |
| } |
| |
| /** |
| * Factored out of inputClassFields and reused in |
| * inputCurrentClassFieldsForReadFields. |
| * |
| * Reads the field (which of an Object type as opposed to a primitive) |
| * described by ObjectStreamField field and returns it. |
| */ |
| private Object inputObjectField(ObjectStreamField field) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IndirectionException, IOException { |
| |
| if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) { |
| return javax.rmi.CORBA.Util.readAny(orbStream); |
| } |
| |
| Object objectValue = null; |
| |
| // fields have an API to provide the actual class |
| // corresponding to the data type |
| // Class type = osc.forClass(); |
| Class fieldType = field.getType(); |
| Class actualType = fieldType; // This may change if stub loaded. |
| |
| // Decide what method call to make based on the fieldType. If |
| // it is a type for which we need to load a stub, convert |
| // the type to the correct stub type. |
| |
| int callType = ValueHandlerImpl.kValueType; |
| boolean narrow = false; |
| |
| if (fieldType.isInterface()) { |
| boolean loadStubClass = false; |
| |
| if (java.rmi.Remote.class.isAssignableFrom(fieldType)) { |
| |
| // RMI Object reference... |
| callType = ValueHandlerImpl.kRemoteType; |
| |
| } else if (org.omg.CORBA.Object.class.isAssignableFrom(fieldType)){ |
| |
| // IDL Object reference... |
| callType = ValueHandlerImpl.kRemoteType; |
| loadStubClass = true; |
| |
| } else if (vhandler.isAbstractBase(fieldType)) { |
| // IDL Abstract Object reference... |
| |
| callType = ValueHandlerImpl.kAbstractType; |
| loadStubClass = true; |
| } else if (ObjectStreamClassCorbaExt.isAbstractInterface(fieldType)) { |
| // RMI Abstract Object reference... |
| |
| callType = ValueHandlerImpl.kAbstractType; |
| } |
| |
| if (loadStubClass) { |
| try { |
| String codebase = Util.getCodebase(fieldType); |
| String repID = vhandler.createForAnyType(fieldType); |
| Class stubType = |
| Utility.loadStubClass(repID, codebase, fieldType); |
| actualType = stubType; |
| } catch (ClassNotFoundException e) { |
| narrow = true; |
| } |
| } else { |
| narrow = true; |
| } |
| } |
| |
| switch (callType) { |
| case ValueHandlerImpl.kRemoteType: |
| if (!narrow) |
| objectValue = (Object)orbStream.read_Object(actualType); |
| else |
| objectValue = Utility.readObjectAndNarrow(orbStream, actualType); |
| break; |
| case ValueHandlerImpl.kAbstractType: |
| if (!narrow) |
| objectValue = (Object)orbStream.read_abstract_interface(actualType); |
| else |
| objectValue = Utility.readAbstractAndNarrow(orbStream, actualType); |
| break; |
| case ValueHandlerImpl.kValueType: |
| objectValue = (Object)orbStream.read_value(actualType); |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new StreamCorruptedException("Unknown callType: " + callType); |
| } |
| |
| return objectValue; |
| } |
| |
| private final boolean mustUseRemoteValueMembers() { |
| return defaultReadObjectFVDMembers != null; |
| } |
| |
| void readFields(java.util.Map fieldToValueMap) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException { |
| |
| if (mustUseRemoteValueMembers()) { |
| inputRemoteMembersForReadFields(fieldToValueMap); |
| } else |
| inputCurrentClassFieldsForReadFields(fieldToValueMap); |
| } |
| |
| private final void inputRemoteMembersForReadFields(java.util.Map fieldToValueMap) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException { |
| |
| // Must have this local variable since defaultReadObjectFVDMembers |
| // may get mangled by recursion. |
| ValueMember fields[] = defaultReadObjectFVDMembers; |
| |
| try { |
| |
| for (int i = 0; i < fields.length; i++) { |
| |
| switch (fields[i].type.kind().value()) { |
| |
| case TCKind._tk_octet: |
| byte byteValue = orbStream.read_octet(); |
| fieldToValueMap.put(fields[i].name, new Byte(byteValue)); |
| break; |
| case TCKind._tk_boolean: |
| boolean booleanValue = orbStream.read_boolean(); |
| fieldToValueMap.put(fields[i].name, new Boolean(booleanValue)); |
| break; |
| case TCKind._tk_char: |
| // Backwards compatibility. Older Sun ORBs sent |
| // _tk_char even though they read and wrote wchars |
| // correctly. |
| // |
| // Fall through to the _tk_wchar case. |
| case TCKind._tk_wchar: |
| char charValue = orbStream.read_wchar(); |
| fieldToValueMap.put(fields[i].name, new Character(charValue)); |
| break; |
| case TCKind._tk_short: |
| short shortValue = orbStream.read_short(); |
| fieldToValueMap.put(fields[i].name, new Short(shortValue)); |
| break; |
| case TCKind._tk_long: |
| int intValue = orbStream.read_long(); |
| fieldToValueMap.put(fields[i].name, new Integer(intValue)); |
| break; |
| case TCKind._tk_longlong: |
| long longValue = orbStream.read_longlong(); |
| fieldToValueMap.put(fields[i].name, new Long(longValue)); |
| break; |
| case TCKind._tk_float: |
| float floatValue = orbStream.read_float(); |
| fieldToValueMap.put(fields[i].name, new Float(floatValue)); |
| break; |
| case TCKind._tk_double: |
| double doubleValue = orbStream.read_double(); |
| fieldToValueMap.put(fields[i].name, new Double(doubleValue)); |
| break; |
| case TCKind._tk_value: |
| case TCKind._tk_objref: |
| case TCKind._tk_value_box: |
| Object objectValue = null; |
| try { |
| objectValue = inputObjectField(fields[i], |
| cbSender); |
| |
| } catch (IndirectionException cdrie) { |
| // The CDR stream had never seen the given offset before, |
| // so check the recursion manager (it will throw an |
| // IOException if it doesn't have a reference, either). |
| objectValue = activeRecursionMgr.getObject(cdrie.offset); |
| } |
| |
| fieldToValueMap.put(fields[i].name, objectValue); |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new StreamCorruptedException("Unknown kind: " |
| + fields[i].type.kind().value()); |
| } |
| } |
| } catch (Throwable t) { |
| StreamCorruptedException result = new StreamCorruptedException(t.getMessage()); |
| result.initCause(t); |
| throw result; |
| } |
| } |
| |
| /** |
| * Called from InputStreamHook. |
| * |
| * Reads the fields of the current class (could be the ones |
| * queried from the remote FVD) and puts them in |
| * the given Map, name to value. Wraps primitives in the |
| * corresponding java.lang Objects. |
| */ |
| private final void inputCurrentClassFieldsForReadFields(java.util.Map fieldToValueMap) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException { |
| |
| ObjectStreamField[] fields = currentClassDesc.getFieldsNoCopy(); |
| |
| int primFields = fields.length - currentClassDesc.objFields; |
| |
| // Handle the primitives first |
| for (int i = 0; i < primFields; ++i) { |
| |
| switch (fields[i].getTypeCode()) { |
| case 'B': |
| byte byteValue = orbStream.read_octet(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Byte(byteValue)); |
| break; |
| case 'Z': |
| boolean booleanValue = orbStream.read_boolean(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Boolean(booleanValue)); |
| break; |
| case 'C': |
| char charValue = orbStream.read_wchar(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Character(charValue)); |
| break; |
| case 'S': |
| short shortValue = orbStream.read_short(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Short(shortValue)); |
| break; |
| case 'I': |
| int intValue = orbStream.read_long(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Integer(intValue)); |
| break; |
| case 'J': |
| long longValue = orbStream.read_longlong(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Long(longValue)); |
| break; |
| case 'F' : |
| float floatValue = orbStream.read_float(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Float(floatValue)); |
| break; |
| case 'D' : |
| double doubleValue = orbStream.read_double(); |
| fieldToValueMap.put(fields[i].getName(), |
| new Double(doubleValue)); |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new InvalidClassException(currentClassDesc.getName()); |
| } |
| } |
| |
| /* Read and set object fields from the input stream. */ |
| if (currentClassDesc.objFields > 0) { |
| for (int i = primFields; i < fields.length; i++) { |
| Object objectValue = null; |
| try { |
| objectValue = inputObjectField(fields[i]); |
| } catch(IndirectionException cdrie) { |
| // The CDR stream had never seen the given offset before, |
| // so check the recursion manager (it will throw an |
| // IOException if it doesn't have a reference, either). |
| objectValue = activeRecursionMgr.getObject(cdrie.offset); |
| } |
| |
| fieldToValueMap.put(fields[i].getName(), objectValue); |
| } |
| } |
| } |
| |
| /* |
| * Read the fields of the specified class from the input stream and set |
| * the values of the fields in the specified object. If the specified |
| * object is null, just consume the fields without setting any values. If |
| * any ObjectStreamField does not have a reflected Field, don't try to set |
| * that field in the object. |
| * |
| * REVISIT -- This code doesn't do what the comment says to when |
| * getField() is null! |
| */ |
| private void inputClassFields(Object o, Class cl, |
| ObjectStreamField[] fields, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException |
| { |
| |
| int primFields = fields.length - currentClassDesc.objFields; |
| |
| if (o != null) { |
| for (int i = 0; i < primFields; ++i) { |
| if (fields[i].getField() == null) |
| continue; |
| |
| inputPrimitiveField(o, cl, fields[i]); |
| } |
| } |
| |
| /* Read and set object fields from the input stream. */ |
| if (currentClassDesc.objFields > 0) { |
| for (int i = primFields; i < fields.length; i++) { |
| Object objectValue = null; |
| |
| try { |
| objectValue = inputObjectField(fields[i]); |
| } catch(IndirectionException cdrie) { |
| // The CDR stream had never seen the given offset before, |
| // so check the recursion manager (it will throw an |
| // IOException if it doesn't have a reference, either). |
| objectValue = activeRecursionMgr.getObject(cdrie.offset); |
| } |
| |
| if ((o == null) || (fields[i].getField() == null)) { |
| continue; |
| } |
| |
| try { |
| Class fieldCl = fields[i].getClazz(); |
| if (objectValue != null && !fieldCl.isInstance(objectValue)) { |
| throw new IllegalArgumentException(); |
| } |
| bridge.putObject( o, fields[i].getFieldID(), objectValue ) ; |
| // reflective code: fields[i].getField().set( o, objectValue ) ; |
| } catch (IllegalArgumentException e) { |
| ClassCastException exc = new ClassCastException("Assigning instance of class " + |
| objectValue.getClass().getName() + |
| " to field " + |
| currentClassDesc.getName() + |
| '#' + |
| fields[i].getField().getName()); |
| exc.initCause( e ) ; |
| throw exc ; |
| } |
| } // end : for loop |
| } |
| } |
| |
| /* |
| * Read the fields of the specified class from the input stream and set |
| * the values of the fields in the specified object. If the specified |
| * object is null, just consume the fields without setting any values. If |
| * any ObjectStreamField does not have a reflected Field, don't try to set |
| * that field in the object. |
| */ |
| private void inputClassFields(Object o, Class cl, |
| ObjectStreamClass osc, |
| ValueMember[] fields, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException |
| { |
| try{ |
| for (int i = 0; i < fields.length; ++i) { |
| try { |
| switch (fields[i].type.kind().value()) { |
| case TCKind._tk_octet: |
| byte byteValue = orbStream.read_octet(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setByteField(o, cl, fields[i].name, byteValue); |
| break; |
| case TCKind._tk_boolean: |
| boolean booleanValue = orbStream.read_boolean(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setBooleanField(o, cl, fields[i].name, booleanValue); |
| break; |
| case TCKind._tk_char: |
| // Backwards compatibility. Older Sun ORBs sent |
| // _tk_char even though they read and wrote wchars |
| // correctly. |
| // |
| // Fall through to the _tk_wchar case. |
| case TCKind._tk_wchar: |
| char charValue = orbStream.read_wchar(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setCharField(o, cl, fields[i].name, charValue); |
| break; |
| case TCKind._tk_short: |
| short shortValue = orbStream.read_short(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setShortField(o, cl, fields[i].name, shortValue); |
| break; |
| case TCKind._tk_long: |
| int intValue = orbStream.read_long(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setIntField(o, cl, fields[i].name, intValue); |
| break; |
| case TCKind._tk_longlong: |
| long longValue = orbStream.read_longlong(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setLongField(o, cl, fields[i].name, longValue); |
| break; |
| case TCKind._tk_float: |
| float floatValue = orbStream.read_float(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setFloatField(o, cl, fields[i].name, floatValue); |
| break; |
| case TCKind._tk_double: |
| double doubleValue = orbStream.read_double(); |
| if ((o != null) && osc.hasField(fields[i])) |
| setDoubleField(o, cl, fields[i].name, doubleValue); |
| break; |
| case TCKind._tk_value: |
| case TCKind._tk_objref: |
| case TCKind._tk_value_box: |
| Object objectValue = null; |
| try { |
| objectValue = inputObjectField(fields[i], sender); |
| } catch (IndirectionException cdrie) { |
| // The CDR stream had never seen the given offset before, |
| // so check the recursion manager (it will throw an |
| // IOException if it doesn't have a reference, either). |
| objectValue = activeRecursionMgr.getObject(cdrie.offset); |
| } |
| |
| if (o == null) |
| continue; |
| try { |
| if (osc.hasField(fields[i])){ |
| setObjectField(o, |
| cl, |
| fields[i].name, |
| objectValue); |
| } else { |
| // REVISIT. Convert to a log message. |
| // This is a normal case when fields have |
| // been added as part of evolution, but |
| // silently skipping can make it hard to |
| // debug if there's an error |
| // System.out.println("**** warning, not setting field: " |
| // + fields[i].name |
| // + " since not on class " |
| // + osc.getName()); |
| |
| } |
| } catch (IllegalArgumentException e) { |
| // XXX I18N, logging needed. |
| ClassCastException cce = new ClassCastException("Assigning instance of class " + |
| objectValue.getClass().getName() + " to field " + fields[i].name); |
| cce.initCause(e) ; |
| throw cce ; |
| } |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new StreamCorruptedException("Unknown kind: " |
| + fields[i].type.kind().value()); |
| } |
| } catch (IllegalArgumentException e) { |
| /* This case should never happen. If the field types |
| are not the same, InvalidClassException is raised when |
| matching the local class to the serialized ObjectStreamClass. */ |
| // XXX I18N, logging needed. |
| ClassCastException cce = new ClassCastException("Assigning instance of class " + fields[i].id + |
| " to field " + currentClassDesc.getName() + '#' + fields[i].name); |
| cce.initCause( e ) ; |
| throw cce ; |
| } |
| } |
| } catch(Throwable t){ |
| // XXX I18N, logging needed. |
| StreamCorruptedException sce = new StreamCorruptedException(t.getMessage()); |
| sce.initCause(t) ; |
| throw sce ; |
| } |
| } |
| |
| private void skipCustomUsingFVD(ValueMember[] fields, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException |
| { |
| readFormatVersion(); |
| boolean calledDefaultWriteObject = readBoolean(); |
| |
| if (calledDefaultWriteObject) |
| throwAwayData(fields, sender); |
| |
| if (getStreamFormatVersion() == 2) { |
| |
| ((ValueInputStream)getOrbStream()).start_value(); |
| ((ValueInputStream)getOrbStream()).end_value(); |
| } |
| } |
| |
| /* |
| * Read the fields of the specified class from the input stream throw data away. |
| * This must handle same switch logic as above. |
| */ |
| private void throwAwayData(ValueMember[] fields, |
| com.sun.org.omg.SendingContext.CodeBase sender) |
| throws InvalidClassException, StreamCorruptedException, |
| ClassNotFoundException, IOException |
| { |
| for (int i = 0; i < fields.length; ++i) { |
| |
| try { |
| |
| switch (fields[i].type.kind().value()) { |
| case TCKind._tk_octet: |
| orbStream.read_octet(); |
| break; |
| case TCKind._tk_boolean: |
| orbStream.read_boolean(); |
| break; |
| case TCKind._tk_char: |
| // Backwards compatibility. Older Sun ORBs sent |
| // _tk_char even though they read and wrote wchars |
| // correctly. |
| // |
| // Fall through to the _tk_wchar case. |
| case TCKind._tk_wchar: |
| orbStream.read_wchar(); |
| break; |
| case TCKind._tk_short: |
| orbStream.read_short(); |
| break; |
| case TCKind._tk_long: |
| orbStream.read_long(); |
| break; |
| case TCKind._tk_longlong: |
| orbStream.read_longlong(); |
| break; |
| case TCKind._tk_float: |
| orbStream.read_float(); |
| break; |
| case TCKind._tk_double: |
| orbStream.read_double(); |
| break; |
| case TCKind._tk_value: |
| case TCKind._tk_objref: |
| case TCKind._tk_value_box: |
| Class type = null; |
| String id = fields[i].id; |
| |
| try { |
| type = vhandler.getClassFromType(id); |
| } |
| catch(ClassNotFoundException cnfe){ |
| // Make sure type = null |
| type = null; |
| } |
| String signature = null; |
| if (type != null) |
| signature = ValueUtility.getSignature(fields[i]); |
| |
| // Read value |
| try { |
| if ((signature != null) && ( signature.equals("Ljava/lang/Object;") || |
| signature.equals("Ljava/io/Serializable;") || |
| signature.equals("Ljava/io/Externalizable;")) ) { |
| javax.rmi.CORBA.Util.readAny(orbStream); |
| } |
| else { |
| // Decide what method call to make based on the type. |
| // |
| // NOTE : Since FullValueDescription does not allow us |
| // to ask whether something is an interface we do not |
| // have the ability to optimize this check. |
| |
| int callType = ValueHandlerImpl.kValueType; |
| |
| if (!vhandler.isSequence(id)) { |
| FullValueDescription fieldFVD = sender.meta(fields[i].id); |
| if (kRemoteTypeCode == fields[i].type) { |
| |
| // RMI Object reference... |
| callType = ValueHandlerImpl.kRemoteType; |
| } else if (fieldFVD.is_abstract) { |
| // RMI Abstract Object reference... |
| |
| callType = ValueHandlerImpl.kAbstractType; |
| } |
| } |
| |
| // Now that we have used the FVD of the field to determine the proper course |
| // of action, it is ok to use the type (Class) from this point forward since |
| // the rep. id for this read will also follow on the wire. |
| |
| switch (callType) { |
| case ValueHandlerImpl.kRemoteType: |
| orbStream.read_Object(); |
| break; |
| case ValueHandlerImpl.kAbstractType: |
| orbStream.read_abstract_interface(); |
| break; |
| case ValueHandlerImpl.kValueType: |
| if (type != null) { |
| orbStream.read_value(type); |
| } else { |
| orbStream.read_value(); |
| } |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new StreamCorruptedException("Unknown callType: " |
| + callType); |
| } |
| } |
| |
| } |
| catch(IndirectionException cdrie) { |
| // Since we are throwing this away, don't bother handling recursion. |
| continue; |
| } |
| |
| break; |
| default: |
| // XXX I18N, logging needed. |
| throw new StreamCorruptedException("Unknown kind: " |
| + fields[i].type.kind().value()); |
| |
| } |
| } catch (IllegalArgumentException e) { |
| /* This case should never happen. If the field types |
| are not the same, InvalidClassException is raised when |
| matching the local class to the serialized ObjectStreamClass. */ |
| // XXX I18N, logging needed. |
| ClassCastException cce = new ClassCastException("Assigning instance of class " + |
| fields[i].id + " to field " + currentClassDesc.getName() + |
| '#' + fields[i].name); |
| cce.initCause(e) ; |
| throw cce ; |
| } |
| } |
| |
| } |
| |
| private static void setObjectField(Object o, Class c, String fieldName, Object v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| Class fieldCl = fld.getType(); |
| if(v != null && !fieldCl.isInstance(v)) { |
| throw new Exception(); |
| } |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putObject( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetObjectField( e, fieldName, |
| o.toString(), |
| v.toString() ) ; |
| } |
| } |
| |
| private static void setBooleanField(Object o, Class c, String fieldName, boolean v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putBoolean( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetBooleanField( e, fieldName, |
| o.toString(), |
| new Boolean(v) ) ; |
| } |
| } |
| |
| private static void setByteField(Object o, Class c, String fieldName, byte v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putByte( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetByteField( e, fieldName, |
| o.toString(), |
| new Byte(v) ) ; |
| } |
| } |
| |
| private static void setCharField(Object o, Class c, String fieldName, char v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putChar( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetCharField( e, fieldName, |
| o.toString(), |
| new Character(v) ) ; |
| } |
| } |
| |
| private static void setShortField(Object o, Class c, String fieldName, short v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putShort( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetShortField( e, fieldName, |
| o.toString(), |
| new Short(v) ) ; |
| } |
| } |
| |
| private static void setIntField(Object o, Class c, String fieldName, int v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putInt( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetIntField( e, fieldName, |
| o.toString(), |
| new Integer(v) ) ; |
| } |
| } |
| |
| private static void setLongField(Object o, Class c, String fieldName, long v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putLong( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetLongField( e, fieldName, |
| o.toString(), |
| new Long(v) ) ; |
| } |
| } |
| |
| private static void setFloatField(Object o, Class c, String fieldName, float v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putFloat( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetFloatField( e, fieldName, |
| o.toString(), |
| new Float(v) ) ; |
| } |
| } |
| |
| private static void setDoubleField(Object o, Class c, String fieldName, double v) |
| { |
| try { |
| Field fld = c.getDeclaredField( fieldName ) ; |
| long key = bridge.objectFieldOffset( fld ) ; |
| bridge.putDouble( o, key, v ) ; |
| } catch (Exception e) { |
| throw utilWrapper.errorSetDoubleField( e, fieldName, |
| o.toString(), |
| new Double(v) ) ; |
| } |
| } |
| |
| /** |
| * This class maintains a map of stream position to |
| * an Object currently being deserialized. It is used |
| * to handle the cases where the are indirections to |
| * an object on the recursion stack. The CDR level |
| * handles indirections to objects previously seen |
| * (and completely deserialized) in the stream. |
| */ |
| static class ActiveRecursionManager |
| { |
| private Map offsetToObjectMap; |
| |
| public ActiveRecursionManager() { |
| // A hash map is unsynchronized and allows |
| // null values |
| offsetToObjectMap = new HashMap(); |
| } |
| |
| // Called right after allocating a new object. |
| // Offset is the starting position in the stream |
| // of the object. |
| public void addObject(int offset, Object value) { |
| offsetToObjectMap.put(new Integer(offset), value); |
| } |
| |
| // If the given starting position doesn't refer |
| // to the beginning of an object currently being |
| // deserialized, this throws an IOException. |
| // Otherwise, it returns a reference to the |
| // object. |
| public Object getObject(int offset) throws IOException { |
| Integer position = new Integer(offset); |
| |
| if (!offsetToObjectMap.containsKey(position)) |
| // XXX I18N, logging needed. |
| throw new IOException("Invalid indirection to offset " |
| + offset); |
| |
| return offsetToObjectMap.get(position); |
| } |
| |
| // Called when an object has been completely |
| // deserialized, so it should no longer be in |
| // this mapping. The CDR level can handle |
| // further indirections. |
| public void removeObject(int offset) { |
| offsetToObjectMap.remove(new Integer(offset)); |
| } |
| |
| // If the given offset doesn't map to an Object, |
| // then it isn't an indirection to an object |
| // currently being deserialized. |
| public boolean containsObject(int offset) { |
| return offsetToObjectMap.containsKey(new Integer(offset)); |
| } |
| } |
| } |