FileDocCategorySizeDatePackage
ValueHandlerImpl.javaAPI DocJava SE 5 API31291Fri Aug 26 14:54:22 BST 2005com.sun.corba.se.impl.io

ValueHandlerImpl.java

/*
 * @(#)ValueHandlerImpl.java	1.65 04/06/21
 *
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
/*
 * Licensed Materials - Property of IBM
 * RMI-IIOP v1.0
 * Copyright IBM Corp. 1998 1999  All Rights Reserved
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

package com.sun.corba.se.impl.io;

import javax.rmi.CORBA.Util;
import javax.rmi.PortableRemoteObject;

import java.util.Hashtable;
import java.util.Stack;
import java.io.IOException;
import java.util.EmptyStackException;

import com.sun.corba.se.impl.util.Utility;
import com.sun.corba.se.impl.io.IIOPInputStream;
import com.sun.corba.se.impl.io.IIOPOutputStream;
import com.sun.corba.se.impl.util.RepositoryId;
import com.sun.corba.se.impl.util.Utility;

import org.omg.CORBA.TCKind;

import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.portable.IndirectionException;
import com.sun.org.omg.SendingContext.CodeBase;
import com.sun.org.omg.SendingContext.CodeBaseHelper;

import java.security.AccessController;
import java.security.PrivilegedAction;
 
import com.sun.corba.se.impl.io.IIOPInputStream.ActiveRecursionManager;

import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.impl.logging.OMGSystemException;
import com.sun.corba.se.impl.logging.UtilSystemException;

public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat {

    // Property to override our maximum stream format version
    public static final String FORMAT_VERSION_PROPERTY
        = "com.sun.CORBA.MaxStreamFormatVersion";

    private static final byte MAX_SUPPORTED_FORMAT_VERSION = (byte)2;
    private static final byte STREAM_FORMAT_VERSION_1 = (byte)1;

    // The ValueHandler's maximum stream format version to advertise,
    // set in a static initializer.
    private static final byte MAX_STREAM_FORMAT_VERSION;

    static {
        MAX_STREAM_FORMAT_VERSION = getMaxStreamFormatVersion();
    }

    // Looks for the FORMAT_VERSION_PROPERTY system property
    // to allow the user to override our default stream format
    // version.  Note that this still only allows them to pick
    // a supported version (1 through MAX_STREAM_FORMAT_VERSION).
    private static byte getMaxStreamFormatVersion() {

        try {

            String propValue = (String) AccessController.doPrivileged(
                                        new PrivilegedAction() {
		public java.lang.Object run() {
	            return System.getProperty(ValueHandlerImpl.FORMAT_VERSION_PROPERTY);
	        }
            });

            // The property wasn't set
            if (propValue == null)
                return MAX_SUPPORTED_FORMAT_VERSION;

            byte result = Byte.parseByte(propValue);

            // REVISIT.  Just set to MAX_SUPPORTED_FORMAT_VERSION
            // or really let the system shutdown with this Error?
            if (result < 1 || result > MAX_SUPPORTED_FORMAT_VERSION)
		// XXX I18N, logging needed.
                throw new ExceptionInInitializerError("Invalid stream format version: "
                                                      + result
                                                      + ".  Valid range is 1 through "
                                                      + MAX_SUPPORTED_FORMAT_VERSION);

            return result;

        } catch (Exception ex) {
            // REVISIT.  Swallow this or really let
            // the system shutdown with this Error?

            Error err = new ExceptionInInitializerError(ex);
	    err.initCause( ex ) ;
	    throw err ;
        }
    }

    public static final short kRemoteType = 0;
    public static final short kAbstractType = 1;
    public static final short kValueType = 2;

    private Hashtable inputStreamPairs = null;
    private Hashtable outputStreamPairs = null;
    private CodeBase codeBase = null;
    private boolean useHashtables = true;
    private boolean isInputStream = true;
    private IIOPOutputStream outputStreamBridge = null;
    private IIOPInputStream inputStreamBridge = null;
    private OMGSystemException omgWrapper = OMGSystemException.get( 
	CORBALogDomains.RPC_ENCODING ) ;
    private UtilSystemException utilWrapper = UtilSystemException.get( 
	CORBALogDomains.RPC_ENCODING ) ;

    // See javax.rmi.CORBA.ValueHandlerMultiFormat
    public byte getMaximumStreamFormatVersion() {
        return MAX_STREAM_FORMAT_VERSION;
    }

    // See javax.rmi.CORBA.ValueHandlerMultiFormat
    public void writeValue(org.omg.CORBA.portable.OutputStream out,
                           java.io.Serializable value,
                           byte streamFormatVersion) {

        if (streamFormatVersion == 2) {
            if (!(out instanceof org.omg.CORBA.portable.ValueOutputStream)) {
		throw omgWrapper.notAValueoutputstream() ;
            }
        } else if (streamFormatVersion != 1) {
	    throw omgWrapper.invalidStreamFormatVersion( 
		new Integer(streamFormatVersion) ) ;
        }

        writeValueWithVersion(out, value, streamFormatVersion);
    }

    public ValueHandlerImpl(){}

    public ValueHandlerImpl(boolean isInputStream) {
	this();
	useHashtables = false;
	this.isInputStream = isInputStream;
    }

    /**
     * Writes the value to the stream using java semantics.
     * @param out The stream to write the value to
     * @param value The value to be written to the stream
     **/
    public void writeValue(org.omg.CORBA.portable.OutputStream _out, 
                           java.io.Serializable value) {
        writeValueWithVersion(_out, value, STREAM_FORMAT_VERSION_1);
    }

    private void writeValueWithVersion(org.omg.CORBA.portable.OutputStream _out,
                                       java.io.Serializable value,
                                       byte streamFormatVersion) {

	org.omg.CORBA_2_3.portable.OutputStream out =
	    (org.omg.CORBA_2_3.portable.OutputStream) _out;

	if (!useHashtables) {
            if (outputStreamBridge == null) {
                outputStreamBridge = createOutputStream();
                outputStreamBridge.setOrbStream(out);
            }

            try {
                outputStreamBridge.increaseRecursionDepth();
                writeValueInternal(outputStreamBridge, out, value, streamFormatVersion);
            } finally {
                outputStreamBridge.decreaseRecursionDepth();
            }

            return;
        }
		
        IIOPOutputStream jdkToOrbOutputStreamBridge = null;

	if (outputStreamPairs == null)
	    outputStreamPairs = new Hashtable();
		
        jdkToOrbOutputStreamBridge = (IIOPOutputStream)outputStreamPairs.get(_out);

        if (jdkToOrbOutputStreamBridge == null) {
            jdkToOrbOutputStreamBridge = createOutputStream();
            jdkToOrbOutputStreamBridge.setOrbStream(out);
            outputStreamPairs.put(_out, jdkToOrbOutputStreamBridge);
        }

        try {

	    jdkToOrbOutputStreamBridge.increaseRecursionDepth();
	    writeValueInternal(jdkToOrbOutputStreamBridge, out, value, streamFormatVersion);
        } finally {
            if (jdkToOrbOutputStreamBridge.decreaseRecursionDepth() == 0) {
                outputStreamPairs.remove(_out);
	    }
        }
    }

    private void writeValueInternal(IIOPOutputStream bridge,
				    org.omg.CORBA_2_3.portable.OutputStream out,
				    java.io.Serializable value,
                                    byte streamFormatVersion)
    {
	Class clazz = value.getClass();

        if (clazz.isArray())
            write_Array(out, value, clazz.getComponentType());
        else
            bridge.simpleWriteObject(value, streamFormatVersion);
    }

    /**
     * Reads a value from the stream using java semantics.
     * @param in The stream to read the value from
     * @param clazz The type of the value to be read in
     * @param sender The sending context runtime
     **/
    public java.io.Serializable readValue(org.omg.CORBA.portable.InputStream _in,
					  int offset, 
					  java.lang.Class clazz, 
					  String repositoryID,
					  org.omg.SendingContext.RunTime _sender)
    {
        // Must use narrow rather than a direct cast to a com.sun
        // class.  Fix for bug 4379539.
	CodeBase sender = CodeBaseHelper.narrow(_sender);

	org.omg.CORBA_2_3.portable.InputStream in = 
	    (org.omg.CORBA_2_3.portable.InputStream) _in;

	if (!useHashtables) {
            if (inputStreamBridge == null) {
                inputStreamBridge = createInputStream();
                inputStreamBridge.setOrbStream(in);
                inputStreamBridge.setSender(sender); //d11638
                // backward compatability 4365188
                inputStreamBridge.setValueHandler(this); 
            }
			
            java.io.Serializable result = null;

            try {

                inputStreamBridge.increaseRecursionDepth();
                result = (java.io.Serializable) readValueInternal(inputStreamBridge, in, offset, clazz, repositoryID, sender);

            } finally {

                if (inputStreamBridge.decreaseRecursionDepth() == 0) {
                    // Indirections are resolved immediately since
                    // the change to the active recursion manager,
                    // so this will never happen.
                }
            }

            return result;
        }
            
        IIOPInputStream jdkToOrbInputStreamBridge = null;
        if (inputStreamPairs == null)
            inputStreamPairs = new Hashtable();
		
        jdkToOrbInputStreamBridge = (IIOPInputStream)inputStreamPairs.get(_in);

        if (jdkToOrbInputStreamBridge == null) {

            jdkToOrbInputStreamBridge = createInputStream();
            jdkToOrbInputStreamBridge.setOrbStream(in);
            jdkToOrbInputStreamBridge.setSender(sender); //d11638
            // backward compatability 4365188
            jdkToOrbInputStreamBridge.setValueHandler(this); 
            inputStreamPairs.put(_in, jdkToOrbInputStreamBridge);
        }

	java.io.Serializable result = null;
		
    	try {
            
	    jdkToOrbInputStreamBridge.increaseRecursionDepth();
	    result = (java.io.Serializable) readValueInternal(jdkToOrbInputStreamBridge, in, offset, clazz, repositoryID, sender);

        } finally {

            if (jdkToOrbInputStreamBridge.decreaseRecursionDepth() == 0) {
                inputStreamPairs.remove(_in);
            }
        }

        return result;
    }

    private java.io.Serializable readValueInternal(IIOPInputStream bridge,
						  org.omg.CORBA_2_3.portable.InputStream in,
						  int offset,
						  java.lang.Class clazz,
						  String repositoryID,
						  com.sun.org.omg.SendingContext.CodeBase sender)
    {
	java.io.Serializable result = null;
		
	if (clazz == null) {
	    // clazz == null indicates an FVD situation for a nonexistant class
	    if (isArray(repositoryID)){
		read_Array(bridge, in, null, sender, offset);
	    } else {
		bridge.simpleSkipObject(repositoryID, sender);
	    }
	    return result;
	}
		
        if (clazz.isArray()) {
            result = (java.io.Serializable)read_Array(bridge, in, clazz, sender, offset);
        } else {
            result = (java.io.Serializable)bridge.simpleReadObject(clazz, repositoryID, sender, offset);
        }

	return result;
    }

    /**
     * Returns the repository ID for the given RMI value Class.
     * @param clz The class to return a repository ID for.
     * @return the repository ID of the Class.
     **/
    public java.lang.String getRMIRepositoryID(java.lang.Class clz) {
	return RepositoryId.createForJavaType(clz);
    }

    /**
     * Indicates whether the given Class performs custom or
     * default marshaling.
     * @param clz The class to test for custom marshaling.
     * @return True if the class performs custom marshaling, false
     * if it does not.
     **/
    public boolean isCustomMarshaled(java.lang.Class clz) {
	return ObjectStreamClass.lookup(clz).isCustomMarshaled();
    }

    /**
     * Returns the CodeBase for this ValueHandler.  This is used by
     * the ORB runtime.  The server sends the service context containing
     * the IOR for this CodeBase on the first GIOP reply.  The clients
     * do the same on the first GIOP request.
     * @return the SendingContext.CodeBase of this ValueHandler.
     **/
    public org.omg.SendingContext.RunTime getRunTimeCodeBase() {
	if (codeBase != null)
	    return codeBase;
	else {
	    codeBase = new FVDCodeBaseImpl();

	    // backward compatability 4365188
            // set the valueHandler so that correct/incorrect RepositoryID
            // calculations can be done based on the ORB version
            FVDCodeBaseImpl fvdImpl = (FVDCodeBaseImpl) codeBase;
            fvdImpl.setValueHandler(this);
	    return codeBase;
	}
    }


    // methods supported for backward compatability so that the appropriate
    // Rep-id calculations take place based on the ORB version

    /**
     *  Returns a boolean of whether or not RepositoryId indicates
     *  FullValueDescriptor.
     *  used for backward compatability
     */

     public boolean useFullValueDescription(Class clazz, String repositoryID)
	throws IOException
     {
	return RepositoryId.useFullValueDescription(clazz, repositoryID);
     }

     public String getClassName(String id)
     {
        RepositoryId repID = RepositoryId.cache.getId(id);
        return repID.getClassName();
     }

     public Class getClassFromType(String id)
        throws ClassNotFoundException
     {
        RepositoryId repId = RepositoryId.cache.getId(id);
        return repId.getClassFromType();
     }

     public Class getAnyClassFromType(String id)
        throws ClassNotFoundException
     {
        RepositoryId repId = RepositoryId.cache.getId(id);
        return repId.getAnyClassFromType();
     }

     public String createForAnyType(Class cl)
     {
        return RepositoryId.createForAnyType(cl);
     }

     public String getDefinedInId(String id)
     {
        RepositoryId repId = RepositoryId.cache.getId(id);
        return repId.getDefinedInId();
     }

     public String getUnqualifiedName(String id)
     {
        RepositoryId repId = RepositoryId.cache.getId(id);
        return repId.getUnqualifiedName();
     }

     public String getSerialVersionUID(String id)
     {
        RepositoryId repId = RepositoryId.cache.getId(id);
        return repId.getSerialVersionUID();
     }


     public boolean isAbstractBase(Class clazz)
     {
        return RepositoryId.isAbstractBase(clazz);
     }

     public boolean isSequence(String id)
     {
        RepositoryId repId = RepositoryId.cache.getId(id);
        return repId.isSequence();
     }

    /**
     * If the value contains a writeReplace method then the result
     * is returned.  Otherwise, the value itself is returned.
     * @return the true value to marshal on the wire.
     **/
    public java.io.Serializable writeReplace(java.io.Serializable value) {
	return ObjectStreamClass.lookup(value.getClass()).writeReplace(value);
    }

    /**
     * Encapsulates writing of Java char arrays so that the 1.3 subclass
     * can override it without exposing internals across packages.  This
     * is a fix for bug 4367783.
     */
    protected void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out,
                                char[] array,
                                int offset,
                                int length)
    {
        out.write_wchar_array(array, offset, length);
    }

    private void write_Array(org.omg.CORBA_2_3.portable.OutputStream out, java.io.Serializable obj, Class type) {

        int i, length;

        if (type.isPrimitive()) {
            if (type == Integer.TYPE) {
		int[] array = (int[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_long_array(array, 0, length);
            } else if (type == Byte.TYPE) {
		byte[] array = (byte[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_octet_array(array, 0, length);
            } else if (type == Long.TYPE) {
		long[] array = (long[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_longlong_array(array, 0, length);
            } else if (type == Float.TYPE) {
		float[] array = (float[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_float_array(array, 0, length);
            } else if (type == Double.TYPE) {
		double[] array = (double[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_double_array(array, 0, length);
            } else if (type == Short.TYPE) {
		short[] array = (short[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_short_array(array, 0, length);
            } else if (type == Character.TYPE) {
		char[] array = (char[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		writeCharArray(out, array, 0, length);
            } else if (type == Boolean.TYPE) {
		boolean[] array = (boolean[])((Object)obj);
		length = array.length;
		out.write_ulong(length);
		out.write_boolean_array(array, 0, length);
            } else {
		// XXX I18N, logging needed.
		throw new Error("Invalid primitive type : " + 
		    obj.getClass().getName());
            }
        } else if (type == java.lang.Object.class) {
            Object[] array = (Object[])((Object)obj);
            length = array.length;
            out.write_ulong(length);
            for (i = 0; i < length; i++) {               
		Util.writeAny(out, array[i]);
	    }
        } else {
            Object[] array = (Object[])((Object)obj);
            length = array.length;
            out.write_ulong(length);
	    int callType = kValueType;
			
	    if (type.isInterface()) { 
		String className = type.getName();
				
		if (java.rmi.Remote.class.isAssignableFrom(type)) {
		    // RMI Object reference...
		    callType = kRemoteType;
		} else if (org.omg.CORBA.Object.class.isAssignableFrom(type)){
		    // IDL Object reference...
		    callType = kRemoteType;
		} else if (RepositoryId.isAbstractBase(type)) {
		    // IDL Abstract Object reference...
		    callType = kAbstractType;
		} else if (ObjectStreamClassCorbaExt.isAbstractInterface(type)) {
		    callType = kAbstractType;
	        }
	    }
			
	    for (i = 0; i < length; i++) {
		switch (callType) {
		case kRemoteType: 
		    Util.writeRemoteObject(out, array[i]);
		    break;
		case kAbstractType: 
		    Util.writeAbstractObject(out,array[i]);
		    break;
		case kValueType:
		    try{
			out.write_value((java.io.Serializable)array[i]);
		    } catch(ClassCastException cce){
			if (array[i] instanceof java.io.Serializable)
			    throw cce;
			else {
			    Utility.throwNotSerializableForCorba(
				array[i].getClass().getName());
			}
		    }
		    break;
		}
	    }
        }
    }

    /**
     * Encapsulates reading of Java char arrays so that the 1.3 subclass
     * can override it without exposing internals across packages.  This
     * is a fix for bug 4367783.
     */
    protected void readCharArray(org.omg.CORBA_2_3.portable.InputStream in,
                                 char[] array,
                                 int offset,
                                 int length)
    {  
        in.read_wchar_array(array, offset, length);
    }

    private java.lang.Object read_Array(IIOPInputStream bridge, 
                                        org.omg.CORBA_2_3.portable.InputStream in,
					Class sequence, 
                                        com.sun.org.omg.SendingContext.CodeBase sender,
                                        int offset) 
    {
    	try {
	    // Read length of coming array
            int length = in.read_ulong();
            int i;

	    if (sequence == null) {
		for (i = 0; i < length; i++)
		    in.read_value();

		return null;
	    }
			
	    Class componentType = sequence.getComponentType();
	    Class actualType = componentType;


            if (componentType.isPrimitive()) {
                if (componentType == Integer.TYPE) {
		    int[] array = new int[length];
		    in.read_long_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Byte.TYPE) {
		    byte[] array = new byte[length];
		    in.read_octet_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Long.TYPE) {
		    long[] array = new long[length];
		    in.read_longlong_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Float.TYPE) {
		    float[] array = new float[length];
		    in.read_float_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Double.TYPE) {
		    double[] array = new double[length];
		    in.read_double_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Short.TYPE) {
		    short[] array = new short[length];
		    in.read_short_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Character.TYPE) {
		    char[] array = new char[length];
		    readCharArray(in, array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else if (componentType == Boolean.TYPE) {
		    boolean[] array = new boolean[length];
		    in.read_boolean_array(array, 0, length);
		    return ((java.io.Serializable)((Object)array));
                } else {
		    // XXX I18N, logging needed.
		    throw new Error("Invalid primitive componentType : " + sequence.getName());
                }
            } else if (componentType == java.lang.Object.class) {
		Object[] array = (Object[])java.lang.reflect.Array.newInstance(
		    componentType, length);

                // Store this object and its beginning position
                // since there might be indirections to it while
                // it's been unmarshalled.
                bridge.activeRecursionMgr.addObject(offset, array);

                for (i = 0; i < length; i++) {
                    Object objectValue = null;
                    try {
                        objectValue = Util.readAny(in);
                    } catch(IndirectionException cdrie) {
                        try {
                            // 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 = bridge.activeRecursionMgr.getObject(
				cdrie.offset);
                        } catch (IOException ie) {
                            // Translate to a MARSHAL exception since
                            // ValueHandlers aren't allowed to throw
                            // IOExceptions
			    throw utilWrapper.invalidIndirection( ie,
				new Integer( cdrie.offset ) ) ;
                        }
                    }
                    
                    array[i] = objectValue;
                }
                return ((java.io.Serializable)((Object)array));
            } else {
		Object[] array = (Object[])java.lang.reflect.Array.newInstance(
		    componentType, length);
                // Store this object and its beginning position
                // since there might be indirections to it while
                // it's been unmarshalled.				
                bridge.activeRecursionMgr.addObject(offset, array);

		// Decide what method call to make based on the componentType.
		// If it is a componentType for which we need to load a stub,
		// convert the componentType to the correct stub type.
				
                int callType = kValueType;
                boolean narrow = false;
				
                if (componentType.isInterface()) { 
                    boolean loadStubClass = false;
                    // String className = componentType.getName();
                        
                    if (java.rmi.Remote.class.isAssignableFrom(componentType)) {
						
                        // RMI Object reference...
                        callType = kRemoteType;
                        
                        // for better performance, load the stub class once
                        // instead of for each element of the array
                        loadStubClass = true;
                    } else if (org.omg.CORBA.Object.class.isAssignableFrom(componentType)){
                        // IDL Object reference...
                        callType = kRemoteType;
                        loadStubClass = true;
                    } else if (RepositoryId.isAbstractBase(componentType)) {
                        // IDL Abstract Object reference...
                        callType = kAbstractType;
                        loadStubClass = true;
                    } else if (ObjectStreamClassCorbaExt.isAbstractInterface(componentType)) {
                        
                        // RMI Abstract Object reference...
                        
                        // componentType = null;
                        callType = kAbstractType;
                    }

                    if (loadStubClass) {
                        try {
                            String codebase = Util.getCodebase(componentType);
                            String repID = RepositoryId.createForAnyType(componentType);
                            Class stubType = 
				Utility.loadStubClass(repID, codebase, componentType); 
			    actualType = stubType;
                        } catch (ClassNotFoundException e) {
                            narrow = true;
                        }
                    } else {
                        narrow = true;
                    }
                }

                for (i = 0; i < length; i++) {
                    
                    try {
                        switch (callType) {
                        case kRemoteType: 
                            if (!narrow)
                                array[i] = (Object)in.read_Object(actualType); 
                            else {
                                array[i] = Utility.readObjectAndNarrow(in, actualType);
                                
                            }
                            break;
                        case kAbstractType: 
                            if (!narrow)
                                array[i] = (Object)in.read_abstract_interface(actualType); 
                            else {
                                array[i] = Utility.readAbstractAndNarrow(in, actualType);
                            }
                            break;
                        case kValueType:
                            array[i] = (Object)in.read_value(actualType);
                            break;
                        }
                    } 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).
                        try {
                            array[i] = bridge.activeRecursionMgr.getObject(
				cdrie.offset);
                        } catch (IOException ioe) {
                            // Translate to a MARSHAL exception since
                            // ValueHandlers aren't allowed to throw
                            // IOExceptions
			    throw utilWrapper.invalidIndirection( ioe,
				new Integer( cdrie.offset ) ) ;
                        }
                    }
                    
                }
                
                return ((java.io.Serializable)((Object)array));
	    }
        } 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.
            bridge.activeRecursionMgr.removeObject(offset);
        }
    }

    private boolean isArray(String repId){
	return RepositoryId.cache.getId(repId).isSequence();
    }

    protected String getOutputStreamClassName() {
        return "com.sun.corba.se.impl.io.IIOPOutputStream";
    }

    private com.sun.corba.se.impl.io.IIOPOutputStream createOutputStream() {
        return (com.sun.corba.se.impl.io.IIOPOutputStream)AccessController.doPrivileged(
	    new StreamFactory(getOutputStreamClassName()));
    }

    protected String getInputStreamClassName() {
        return "com.sun.corba.se.impl.io.IIOPInputStream";
    }

    private com.sun.corba.se.impl.io.IIOPInputStream createInputStream() {
        return (com.sun.corba.se.impl.io.IIOPInputStream)AccessController.doPrivileged(
	    new StreamFactory(getInputStreamClassName()));
    }

    /**
     * Instantiates a class of the given name using the system ClassLoader
     * as part of a PrivilegedAction.
     *
     * It's private final so hopefully people can't grab it outside of
     * this class.
     *
     * If you're worried that someone could subclass ValueHandlerImpl,
     * install his own streams, and snoop what's on the wire:
     * Someone can do that only if he's allowed to use the feature
     * of installing his own javax.rmi.CORBA.Util delegate (via a
     * JVM property or orb.properties file, read the first time the
     * Util class is used).  If he can do that, he can snoop
     * anything on the wire, anyway, without abusing the
     * StreamFactory class.
     */
    private static final class StreamFactory implements PrivilegedAction {
        private String className;

        public StreamFactory (String _className) {
            className = _className;
        }

        public Object run() {
            try {
                // Note: We must use the system ClassLoader here
                // since we want to load classes outside of the
                // core JDK when running J2EE Pure ORB and
                // talking to Kestrel.
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                if (cl == null)
                    cl = ClassLoader.getSystemClassLoader();

                Class streamClass = cl.loadClass(className);

                // Since the ClassLoader should cache the class, this isn't
                // as expensive as it looks.
                return streamClass.newInstance();

            } catch(Throwable t) {
                InternalError ie = new InternalError( "Error loading " + className ) ;
		ie.initCause( t ) ;
		throw ie ;
            }
        }
    }

    /**
     * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this.
     * The correct behavior is for a Java char to map to a CORBA wchar,
     * but our older code mapped it to a CORBA char.
     */
    protected TCKind getJavaCharTCKind() {
        return TCKind.tk_wchar;
    }
}