/*
* Copyright (c) 1998, 2015, 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.IOException;
import java.io.StreamCorruptedException;
import java.io.ObjectInputValidation;
import java.io.NotActiveException;
import java.io.InvalidObjectException;
import java.io.InvalidClassException;
import java.io.OptionalDataException;
import java.io.Externalizable;
import java.io.EOFException;
import java.lang.reflect.*;
import java.util.Vector;
import java.util.Enumeration;
import sun.corba.Bridge ;
import java.security.AccessController ;
import java.security.PrivilegedAction ;
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.CORBA.Util;
import javax.rmi.CORBA.ValueHandler;
import java.security.*;
import java.util.*;
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
/**
* 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;
// 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;
/**
* 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.
Throws: - ClassNotFoundException – Class of a serialized object
cannot be found.
- InvalidClassException – Something is wrong with a class used by
serialization.
- StreamCorruptedException – Control information in the
stream is inconsistent.
- OptionalDataException – Primitive data was found in the
stream instead of objects.
- IOException – Any of the usual Input/Output related exceptions.
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.
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.
Since: JDK1.1
/**
* 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 synchronized 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 synchronized 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 synchronized 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".
See Also: - ObjectInputStream()
- ObjectInputStream.readObject
Returns: the Object read from the stream. Since: JDK 1.2
/**
* 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.
Throws: - ClassNotFoundException – if the class of a serialized
object could not be found.
- IOException – if an I/O error occurs.
- NotActiveException – if the stream is not currently reading
objects.
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. Since: JDK1.1
/**
* 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
*/
final synchronized void defaultReadObjectDelegate()
/* throws IOException, ClassNotFoundException, NotActiveException */
{
try {
if (currentObject == null || currentClassDesc == null)
// XXX I18N, logging needed.
throw new NotActiveException("defaultReadObjectDelegate");
if (!currentClassDesc.forClass().isAssignableFrom(
currentObject.getClass())) {
throw new IOException("Object Type mismatch");
}
// 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.
Throws: - SecurityException – The classloader of this stream object is non-null.
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.
When enabled the resolveObject method is called for every object
being deserialized.
Since: JDK1.1
/**
* 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.
/**
* 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 = bridge.newOptionalDataExceptionForSerialization(true);
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 synchronized 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
if (currentClass.getName().equals("java.lang.String")) {
return this.readUTF();
}
/* 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.hasReadObject());
} 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.
/**
* 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 synchronized 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.hasReadObject());
}
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.
/**
* 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
{
try {
return osc.invokeReadObject( obj, this ) ;
} 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");
}
}
/*
* 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.
/**
* 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();
if (field.getField() != null) {
bridge.putByte( o, field.getFieldID(), byteValue ) ;
//reflective code: field.getField().setByte( o, byteValue ) ;
}
break;
case 'Z':
boolean booleanValue = orbStream.read_boolean();
if (field.getField() != null) {
bridge.putBoolean( o, field.getFieldID(), booleanValue ) ;
//reflective code: field.getField().setBoolean( o, booleanValue ) ;
}
break;
case 'C':
char charValue = orbStream.read_wchar();
if (field.getField() != null) {
bridge.putChar( o, field.getFieldID(), charValue ) ;
//reflective code: field.getField().setChar( o, charValue ) ;
}
break;
case 'S':
short shortValue = orbStream.read_short();
if (field.getField() != null) {
bridge.putShort( o, field.getFieldID(), shortValue ) ;
//reflective code: field.getField().setShort( o, shortValue ) ;
}
break;
case 'I':
int intValue = orbStream.read_long();
if (field.getField() != null) {
bridge.putInt( o, field.getFieldID(), intValue ) ;
//reflective code: field.getField().setInt( o, intValue ) ;
}
break;
case 'J':
long longValue = orbStream.read_longlong();
if (field.getField() != null) {
bridge.putLong( o, field.getFieldID(), longValue ) ;
//reflective code: field.getField().setLong( o, longValue ) ;
}
break;
case 'F' :
float floatValue = orbStream.read_float();
if (field.getField() != null) {
bridge.putFloat( o, field.getFieldID(), floatValue ) ;
//reflective code: field.getField().setFloat( o, floatValue ) ;
}
break;
case 'D' :
double doubleValue = orbStream.read_double();
if (field.getField() != null) {
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.
/**
* 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.
/**
* 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;
// this will leave primitives in the inputstream
// should really consume and discard where necessary
if (o != null) {
for (int i = 0; i < primFields; ++i) {
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.isAssignableFrom(
objectValue.getClass()))) {
throw new IllegalArgumentException("Field mismatch");
}
Field declaredClassField = null;
final String inputStreamFieldName = fields[i].getName();
try {
declaredClassField = getDeclaredField( cl, inputStreamFieldName);
} catch (PrivilegedActionException paEx) {
throw new IllegalArgumentException(
(NoSuchFieldException) paEx.getException());
} catch (SecurityException secEx) {
throw new IllegalArgumentException(secEx);
} catch (NullPointerException npEx) {
continue;
} catch (NoSuchFieldException e) {
continue;
}
if (declaredClassField == null) {
continue;
}
Class<?> declaredFieldClass = declaredClassField.getType();
// check input field type is a declared field type
// input field is a subclass of the declared field
if (!declaredFieldClass.isAssignableFrom(fieldCl)) {
throw new IllegalArgumentException(
"Field Type mismatch");
}
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 iaEx) {
String objectValueClassName = "null";
String currentClassDescClassName = "null";
String fieldName = "null";
if (objectValue != null) {
objectValueClassName = objectValue.getClass().getName();
}
if (currentClassDesc != null) {
currentClassDescClassName = currentClassDesc.getName();
}
if (fields[i] != null && fields[i].getField() != null) {
fieldName = fields[i].getField().getName();
}
ClassCastException ccEx = new ClassCastException(
"Assigning instance of class " + objectValueClassName
+ " to field " + currentClassDescClassName + '#' + fieldName);
ccEx.initCause( iaEx ) ;
throw ccEx ;
}
} // 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 = getDeclaredField( c, 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) {
if (o != null) {
throw utilWrapper.errorSetObjectField( e, fieldName,
o.toString(),
v.toString() ) ;
} else {
throw utilWrapper.errorSetObjectField( e, fieldName,
"null " + c.getName() + " object",
v.toString() ) ;
}
}
}
private static void setBooleanField(Object o, Class<?> c, String fieldName, boolean v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Boolean.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putBoolean( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetBooleanField( e, fieldName,
o.toString(),
new Boolean(v) ) ;
} else {
throw utilWrapper.errorSetBooleanField( e, fieldName,
"null " + c.getName() + " object",
new Boolean(v) ) ;
}
}
}
private static void setByteField(Object o, Class<?> c, String fieldName, byte v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Byte.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putByte( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetByteField( e, fieldName,
o.toString(),
new Byte(v) ) ;
} else {
throw utilWrapper.errorSetByteField( e, fieldName,
"null " + c.getName() + " object",
new Byte(v) ) ;
}
}
}
private static void setCharField(Object o, Class<?> c, String fieldName, char v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Character.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putChar( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetCharField( e, fieldName,
o.toString(),
new Character(v) ) ;
} else {
throw utilWrapper.errorSetCharField( e, fieldName,
"null " + c.getName() + " object",
new Character(v) ) ;
}
}
}
private static void setShortField(Object o, Class<?> c, String fieldName, short v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Short.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putShort( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetShortField( e, fieldName,
o.toString(),
new Short(v) ) ;
} else {
throw utilWrapper.errorSetShortField( e, fieldName,
"null " + c.getName() + " object",
new Short(v) ) ;
}
}
}
private static void setIntField(Object o, Class<?> c, String fieldName, int v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Integer.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putInt( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetIntField( e, fieldName,
o.toString(),
new Integer(v) ) ;
} else {
throw utilWrapper.errorSetIntField( e, fieldName,
"null " + c.getName() + " object",
new Integer(v) ) ;
}
}
}
private static void setLongField(Object o, Class<?> c, String fieldName, long v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Long.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putLong( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetLongField( e, fieldName,
o.toString(),
new Long(v) ) ;
} else {
throw utilWrapper.errorSetLongField( e, fieldName,
"null " + c.getName() + " object",
new Long(v) ) ;
}
}
}
private static void setFloatField(Object o, Class<?> c, String fieldName, float v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Float.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putFloat( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetFloatField( e, fieldName,
o.toString(),
new Float(v) ) ;
} else {
throw utilWrapper.errorSetFloatField( e, fieldName,
"null " + c.getName() + " object",
new Float(v) ) ;
}
}
}
private static void setDoubleField(Object o, Class<?> c, String fieldName, double v)
{
try {
Field fld = getDeclaredField( c, fieldName ) ;
if ((fld != null) && (fld.getType() == Double.TYPE)) {
long key = bridge.objectFieldOffset( fld ) ;
bridge.putDouble( o, key, v ) ;
} else {
throw new InvalidObjectException("Field Type mismatch");
}
} catch (Exception e) {
if (o != null) {
throw utilWrapper.errorSetDoubleField( e, fieldName,
o.toString(),
new Double(v) ) ;
} else {
throw utilWrapper.errorSetDoubleField( e, fieldName,
"null " + c.getName() + " object",
new Double(v) ) ;
}
}
}
private static Field getDeclaredField(final Class<?> c,
final String fieldName)
throws PrivilegedActionException, NoSuchFieldException, SecurityException {
if (System.getSecurityManager() == null) {
return c.getDeclaredField(fieldName);
} else {
return AccessController
.doPrivileged(new PrivilegedExceptionAction<Field>() {
public Field run() throws NoSuchFieldException {
return c.getDeclaredField(fieldName);
}
});
}
}
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.
/**
* 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<Integer, Object> 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));
}
}
}