blob: 7eff7c3f9aa4015e645005837fe10ac0f98cee4a [file] [log] [blame]
/*
* 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.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 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".
*
* @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
*/
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.
* @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 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.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 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.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();
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.
*/
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, final 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) {
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, final Class<?> c, final 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.
*/
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));
}
}
}