ValueHandlerImpl.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25/*
26 * Licensed Materials - Property of IBM
27 * RMI-IIOP v1.0
28 * Copyright IBM Corp. 1998 1999  All Rights Reserved
29 *
30 */
31
32package com.sun.corba.se.impl.io;
33
34import javax.rmi.CORBA.Util;
35
36import java.util.Hashtable;
37import java.io.IOException;
38
39import com.sun.corba.se.impl.util.RepositoryId;
40import com.sun.corba.se.impl.util.Utility;
41
42import org.omg.CORBA.TCKind;
43
44import org.omg.CORBA.portable.IndirectionException;
45import com.sun.org.omg.SendingContext.CodeBase;
46import com.sun.org.omg.SendingContext.CodeBaseHelper;
47
48import java.security.AccessController;
49import java.security.PrivilegedAction;
50import java.security.PrivilegedExceptionAction;
51
52import com.sun.corba.se.spi.logging.CORBALogDomains;
53import com.sun.corba.se.impl.logging.OMGSystemException;
54import com.sun.corba.se.impl.logging.UtilSystemException;
55
56public final class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat {
57
58    // Property to override our maximum stream format version
59    public static final String FORMAT_VERSION_PROPERTY
60        = "com.sun.CORBA.MaxStreamFormatVersion";
61
62    private static final byte MAX_SUPPORTED_FORMAT_VERSION = (byte)2;
63    private static final byte STREAM_FORMAT_VERSION_1 = (byte)1;
64
65    // The ValueHandler's maximum stream format version to advertise,
66    // set in a static initializer.
67    private static final byte MAX_STREAM_FORMAT_VERSION;
68
69    static {
70        MAX_STREAM_FORMAT_VERSION = getMaxStreamFormatVersion();
71    }
72
73    // Looks for the FORMAT_VERSION_PROPERTY system property
74    // to allow the user to override our default stream format
75    // version.  Note that this still only allows them to pick
76    // a supported version (1 through MAX_STREAM_FORMAT_VERSION).
77    private static byte getMaxStreamFormatVersion() {
78
79        try {
80
81            String propValue = (String) AccessController.doPrivileged(
82                                        new PrivilegedAction() {
83                public java.lang.Object run() {
84                    return System.getProperty(ValueHandlerImpl.FORMAT_VERSION_PROPERTY);
85                }
86            });
87
88            // The property wasn't set
89            if (propValue == null)
90                return MAX_SUPPORTED_FORMAT_VERSION;
91
92            byte result = Byte.parseByte(propValue);
93
94            // REVISIT.  Just set to MAX_SUPPORTED_FORMAT_VERSION
95            // or really let the system shutdown with this Error?
96            if (result < 1 || result > MAX_SUPPORTED_FORMAT_VERSION)
97                // XXX I18N, logging needed.
98                throw new ExceptionInInitializerError("Invalid stream format version: "
99                                                      + result
100                                                      + ".  Valid range is 1 through "
101                                                      + MAX_SUPPORTED_FORMAT_VERSION);
102
103            return result;
104
105        } catch (Exception ex) {
106            // REVISIT.  Swallow this or really let
107            // the system shutdown with this Error?
108
109            Error err = new ExceptionInInitializerError(ex);
110            err.initCause( ex ) ;
111            throw err ;
112        }
113    }
114
115    public static final short kRemoteType = 0;
116    public static final short kAbstractType = 1;
117    public static final short kValueType = 2;
118
119    private Hashtable inputStreamPairs = null;
120    private Hashtable outputStreamPairs = null;
121    private CodeBase codeBase = null;
122    private boolean useHashtables = true;
123    private boolean isInputStream = true;
124    private IIOPOutputStream outputStreamBridge = null;
125    private IIOPInputStream inputStreamBridge = null;
126    private OMGSystemException omgWrapper = OMGSystemException.get(
127        CORBALogDomains.RPC_ENCODING ) ;
128    private UtilSystemException utilWrapper = UtilSystemException.get(
129        CORBALogDomains.RPC_ENCODING ) ;
130
131    // See javax.rmi.CORBA.ValueHandlerMultiFormat
132    public byte getMaximumStreamFormatVersion() {
133        return MAX_STREAM_FORMAT_VERSION;
134    }
135
136    // See javax.rmi.CORBA.ValueHandlerMultiFormat
137    public void writeValue(org.omg.CORBA.portable.OutputStream out,
138                           java.io.Serializable value,
139                           byte streamFormatVersion) {
140
141        if (streamFormatVersion == 2) {
142            if (!(out instanceof org.omg.CORBA.portable.ValueOutputStream)) {
143                throw omgWrapper.notAValueoutputstream() ;
144            }
145        } else if (streamFormatVersion != 1) {
146            throw omgWrapper.invalidStreamFormatVersion(
147                new Integer(streamFormatVersion) ) ;
148        }
149
150        writeValueWithVersion(out, value, streamFormatVersion);
151    }
152
153    private ValueHandlerImpl(){}
154
155    private ValueHandlerImpl(boolean isInputStream) {
156        this();
157        useHashtables = false;
158        this.isInputStream = isInputStream;
159    }
160
161    static ValueHandlerImpl getInstance() {
162        return new ValueHandlerImpl();
163    }
164
165    static ValueHandlerImpl getInstance(boolean isInputStream) {
166        return new ValueHandlerImpl(isInputStream);
167    }
168
169    /**
170     * Writes the value to the stream using java semantics.
171     * @param out The stream to write the value to
172     * @param value The value to be written to the stream
173     **/
174    public void writeValue(org.omg.CORBA.portable.OutputStream _out,
175                           java.io.Serializable value) {
176        writeValueWithVersion(_out, value, STREAM_FORMAT_VERSION_1);
177    }
178
179    private void writeValueWithVersion(org.omg.CORBA.portable.OutputStream _out,
180                                       java.io.Serializable value,
181                                       byte streamFormatVersion) {
182
183        org.omg.CORBA_2_3.portable.OutputStream out =
184            (org.omg.CORBA_2_3.portable.OutputStream) _out;
185
186        if (!useHashtables) {
187            if (outputStreamBridge == null) {
188                outputStreamBridge = createOutputStream();
189                outputStreamBridge.setOrbStream(out);
190            }
191
192            try {
193                outputStreamBridge.increaseRecursionDepth();
194                writeValueInternal(outputStreamBridge, out, value, streamFormatVersion);
195            } finally {
196                outputStreamBridge.decreaseRecursionDepth();
197            }
198
199            return;
200        }
201
202        IIOPOutputStream jdkToOrbOutputStreamBridge = null;
203
204        if (outputStreamPairs == null)
205            outputStreamPairs = new Hashtable();
206
207        jdkToOrbOutputStreamBridge = (IIOPOutputStream)outputStreamPairs.get(_out);
208
209        if (jdkToOrbOutputStreamBridge == null) {
210            jdkToOrbOutputStreamBridge = createOutputStream();
211            jdkToOrbOutputStreamBridge.setOrbStream(out);
212            outputStreamPairs.put(_out, jdkToOrbOutputStreamBridge);
213        }
214
215        try {
216
217            jdkToOrbOutputStreamBridge.increaseRecursionDepth();
218            writeValueInternal(jdkToOrbOutputStreamBridge, out, value, streamFormatVersion);
219        } finally {
220            if (jdkToOrbOutputStreamBridge.decreaseRecursionDepth() == 0) {
221                outputStreamPairs.remove(_out);
222            }
223        }
224    }
225
226    private void writeValueInternal(IIOPOutputStream bridge,
227                                    org.omg.CORBA_2_3.portable.OutputStream out,
228                                    java.io.Serializable value,
229                                    byte streamFormatVersion)
230    {
231        Class clazz = value.getClass();
232
233        if (clazz.isArray())
234            write_Array(out, value, clazz.getComponentType());
235        else
236            bridge.simpleWriteObject(value, streamFormatVersion);
237    }
238
239    /**
240     * Reads a value from the stream using java semantics.
241     * @param in The stream to read the value from
242     * @param clazz The type of the value to be read in
243     * @param sender The sending context runtime
244     **/
245    public java.io.Serializable readValue(org.omg.CORBA.portable.InputStream _in,
246                                          int offset,
247                                          java.lang.Class clazz,
248                                          String repositoryID,
249                                          org.omg.SendingContext.RunTime _sender)
250    {
251        // Must use narrow rather than a direct cast to a com.sun
252        // class.  Fix for bug 4379539.
253        CodeBase sender = CodeBaseHelper.narrow(_sender);
254
255        org.omg.CORBA_2_3.portable.InputStream in =
256            (org.omg.CORBA_2_3.portable.InputStream) _in;
257
258        if (!useHashtables) {
259            if (inputStreamBridge == null) {
260                inputStreamBridge = createInputStream();
261                inputStreamBridge.setOrbStream(in);
262                inputStreamBridge.setSender(sender); //d11638
263                // backward compatability 4365188
264                inputStreamBridge.setValueHandler(this);
265            }
266
267            java.io.Serializable result = null;
268
269            try {
270
271                inputStreamBridge.increaseRecursionDepth();
272                result = (java.io.Serializable) readValueInternal(inputStreamBridge, in, offset, clazz, repositoryID, sender);
273
274            } finally {
275
276                if (inputStreamBridge.decreaseRecursionDepth() == 0) {
277                    // Indirections are resolved immediately since
278                    // the change to the active recursion manager,
279                    // so this will never happen.
280                }
281            }
282
283            return result;
284        }
285
286        IIOPInputStream jdkToOrbInputStreamBridge = null;
287        if (inputStreamPairs == null)
288            inputStreamPairs = new Hashtable();
289
290        jdkToOrbInputStreamBridge = (IIOPInputStream)inputStreamPairs.get(_in);
291
292        if (jdkToOrbInputStreamBridge == null) {
293
294            jdkToOrbInputStreamBridge = createInputStream();
295            jdkToOrbInputStreamBridge.setOrbStream(in);
296            jdkToOrbInputStreamBridge.setSender(sender); //d11638
297            // backward compatability 4365188
298            jdkToOrbInputStreamBridge.setValueHandler(this);
299            inputStreamPairs.put(_in, jdkToOrbInputStreamBridge);
300        }
301
302        java.io.Serializable result = null;
303
304        try {
305
306            jdkToOrbInputStreamBridge.increaseRecursionDepth();
307            result = (java.io.Serializable) readValueInternal(jdkToOrbInputStreamBridge, in, offset, clazz, repositoryID, sender);
308
309        } finally {
310
311            if (jdkToOrbInputStreamBridge.decreaseRecursionDepth() == 0) {
312                inputStreamPairs.remove(_in);
313            }
314        }
315
316        return result;
317    }
318
319    private java.io.Serializable readValueInternal(IIOPInputStream bridge,
320                                                  org.omg.CORBA_2_3.portable.InputStream in,
321                                                  int offset,
322                                                  java.lang.Class clazz,
323                                                  String repositoryID,
324                                                  com.sun.org.omg.SendingContext.CodeBase sender)
325    {
326        java.io.Serializable result = null;
327
328        if (clazz == null) {
329            // clazz == null indicates an FVD situation for a nonexistant class
330            if (isArray(repositoryID)){
331                read_Array(bridge, in, null, sender, offset);
332            } else {
333                bridge.simpleSkipObject(repositoryID, sender);
334            }
335            return result;
336        }
337
338        if (clazz.isArray()) {
339            result = (java.io.Serializable)read_Array(bridge, in, clazz, sender, offset);
340        } else {
341            result = (java.io.Serializable)bridge.simpleReadObject(clazz, repositoryID, sender, offset);
342        }
343
344        return result;
345    }
346
347    /**
348     * Returns the repository ID for the given RMI value Class.
349     * @param clz The class to return a repository ID for.
350     * @return the repository ID of the Class.
351     **/
352    public java.lang.String getRMIRepositoryID(java.lang.Class clz) {
353        return RepositoryId.createForJavaType(clz);
354    }
355
356    /**
357     * Indicates whether the given Class performs custom or
358     * default marshaling.
359     * @param clz The class to test for custom marshaling.
360     * @return True if the class performs custom marshaling, false
361     * if it does not.
362     **/
363    public boolean isCustomMarshaled(java.lang.Class clz) {
364        return ObjectStreamClass.lookup(clz).isCustomMarshaled();
365    }
366
367    /**
368     * Returns the CodeBase for this ValueHandler.  This is used by
369     * the ORB runtime.  The server sends the service context containing
370     * the IOR for this CodeBase on the first GIOP reply.  The clients
371     * do the same on the first GIOP request.
372     * @return the SendingContext.CodeBase of this ValueHandler.
373     **/
374    public org.omg.SendingContext.RunTime getRunTimeCodeBase() {
375        if (codeBase != null)
376            return codeBase;
377        else {
378            codeBase = new FVDCodeBaseImpl();
379
380            // backward compatability 4365188
381            // set the valueHandler so that correct/incorrect RepositoryID
382            // calculations can be done based on the ORB version
383            FVDCodeBaseImpl fvdImpl = (FVDCodeBaseImpl) codeBase;
384            fvdImpl.setValueHandler(this);
385            return codeBase;
386        }
387    }
388
389
390    // methods supported for backward compatability so that the appropriate
391    // Rep-id calculations take place based on the ORB version
392
393    /**
394     *  Returns a boolean of whether or not RepositoryId indicates
395     *  FullValueDescriptor.
396     *  used for backward compatability
397     */
398
399     public boolean useFullValueDescription(Class clazz, String repositoryID)
400        throws IOException
401     {
402        return RepositoryId.useFullValueDescription(clazz, repositoryID);
403     }
404
405     public String getClassName(String id)
406     {
407        RepositoryId repID = RepositoryId.cache.getId(id);
408        return repID.getClassName();
409     }
410
411     public Class getClassFromType(String id)
412        throws ClassNotFoundException
413     {
414        RepositoryId repId = RepositoryId.cache.getId(id);
415        return repId.getClassFromType();
416     }
417
418     public Class getAnyClassFromType(String id)
419        throws ClassNotFoundException
420     {
421        RepositoryId repId = RepositoryId.cache.getId(id);
422        return repId.getAnyClassFromType();
423     }
424
425     public String createForAnyType(Class cl)
426     {
427        return RepositoryId.createForAnyType(cl);
428     }
429
430     public String getDefinedInId(String id)
431     {
432        RepositoryId repId = RepositoryId.cache.getId(id);
433        return repId.getDefinedInId();
434     }
435
436     public String getUnqualifiedName(String id)
437     {
438        RepositoryId repId = RepositoryId.cache.getId(id);
439        return repId.getUnqualifiedName();
440     }
441
442     public String getSerialVersionUID(String id)
443     {
444        RepositoryId repId = RepositoryId.cache.getId(id);
445        return repId.getSerialVersionUID();
446     }
447
448
449     public boolean isAbstractBase(Class clazz)
450     {
451        return RepositoryId.isAbstractBase(clazz);
452     }
453
454     public boolean isSequence(String id)
455     {
456        RepositoryId repId = RepositoryId.cache.getId(id);
457        return repId.isSequence();
458     }
459
460    /**
461     * If the value contains a writeReplace method then the result
462     * is returned.  Otherwise, the value itself is returned.
463     * @return the true value to marshal on the wire.
464     **/
465    public java.io.Serializable writeReplace(java.io.Serializable value) {
466        return ObjectStreamClass.lookup(value.getClass()).writeReplace(value);
467    }
468
469    private void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out,
470                                char[] array,
471                                int offset,
472                                int length)
473    {
474        out.write_wchar_array(array, offset, length);
475    }
476
477    private void write_Array(org.omg.CORBA_2_3.portable.OutputStream out, java.io.Serializable obj, Class type) {
478
479        int i, length;
480
481        if (type.isPrimitive()) {
482            if (type == Integer.TYPE) {
483                int[] array = (int[])((Object)obj);
484                length = array.length;
485                out.write_ulong(length);
486                out.write_long_array(array, 0, length);
487            } else if (type == Byte.TYPE) {
488                byte[] array = (byte[])((Object)obj);
489                length = array.length;
490                out.write_ulong(length);
491                out.write_octet_array(array, 0, length);
492            } else if (type == Long.TYPE) {
493                long[] array = (long[])((Object)obj);
494                length = array.length;
495                out.write_ulong(length);
496                out.write_longlong_array(array, 0, length);
497            } else if (type == Float.TYPE) {
498                float[] array = (float[])((Object)obj);
499                length = array.length;
500                out.write_ulong(length);
501                out.write_float_array(array, 0, length);
502            } else if (type == Double.TYPE) {
503                double[] array = (double[])((Object)obj);
504                length = array.length;
505                out.write_ulong(length);
506                out.write_double_array(array, 0, length);
507            } else if (type == Short.TYPE) {
508                short[] array = (short[])((Object)obj);
509                length = array.length;
510                out.write_ulong(length);
511                out.write_short_array(array, 0, length);
512            } else if (type == Character.TYPE) {
513                char[] array = (char[])((Object)obj);
514                length = array.length;
515                out.write_ulong(length);
516                writeCharArray(out, array, 0, length);
517            } else if (type == Boolean.TYPE) {
518                boolean[] array = (boolean[])((Object)obj);
519                length = array.length;
520                out.write_ulong(length);
521                out.write_boolean_array(array, 0, length);
522            } else {
523                // XXX I18N, logging needed.
524                throw new Error("Invalid primitive type : " +
525                    obj.getClass().getName());
526            }
527        } else if (type == java.lang.Object.class) {
528            Object[] array = (Object[])((Object)obj);
529            length = array.length;
530            out.write_ulong(length);
531            for (i = 0; i < length; i++) {
532                Util.writeAny(out, array[i]);
533            }
534        } else {
535            Object[] array = (Object[])((Object)obj);
536            length = array.length;
537            out.write_ulong(length);
538            int callType = kValueType;
539
540            if (type.isInterface()) {
541                String className = type.getName();
542
543                if (java.rmi.Remote.class.isAssignableFrom(type)) {
544                    // RMI Object reference...
545                    callType = kRemoteType;
546                } else if (org.omg.CORBA.Object.class.isAssignableFrom(type)){
547                    // IDL Object reference...
548                    callType = kRemoteType;
549                } else if (RepositoryId.isAbstractBase(type)) {
550                    // IDL Abstract Object reference...
551                    callType = kAbstractType;
552                } else if (ObjectStreamClassCorbaExt.isAbstractInterface(type)) {
553                    callType = kAbstractType;
554                }
555            }
556
557            for (i = 0; i < length; i++) {
558                switch (callType) {
559                case kRemoteType:
560                    Util.writeRemoteObject(out, array[i]);
561                    break;
562                case kAbstractType:
563                    Util.writeAbstractObject(out,array[i]);
564                    break;
565                case kValueType:
566                    try{
567                        out.write_value((java.io.Serializable)array[i]);
568                    } catch(ClassCastException cce){
569                        if (array[i] instanceof java.io.Serializable)
570                            throw cce;
571                        else {
572                            Utility.throwNotSerializableForCorba(
573                                array[i].getClass().getName());
574                        }
575                    }
576                    break;
577                }
578            }
579        }
580    }
581
582    private void readCharArray(org.omg.CORBA_2_3.portable.InputStream in,
583                                 char[] array,
584                                 int offset,
585                                 int length)
586    {
587        in.read_wchar_array(array, offset, length);
588    }
589
590    private java.lang.Object read_Array(IIOPInputStream bridge,
591                                        org.omg.CORBA_2_3.portable.InputStream in,
592                                        Class sequence,
593                                        com.sun.org.omg.SendingContext.CodeBase sender,
594                                        int offset)
595    {
596        try {
597            // Read length of coming array
598            int length = in.read_ulong();
599            int i;
600
601            if (sequence == null) {
602                for (i = 0; i < length; i++)
603                    in.read_value();
604
605                return null;
606            }
607
608            Class componentType = sequence.getComponentType();
609            Class actualType = componentType;
610
611
612            if (componentType.isPrimitive()) {
613                if (componentType == Integer.TYPE) {
614                    int[] array = new int[length];
615                    in.read_long_array(array, 0, length);
616                    return ((java.io.Serializable)((Object)array));
617                } else if (componentType == Byte.TYPE) {
618                    byte[] array = new byte[length];
619                    in.read_octet_array(array, 0, length);
620                    return ((java.io.Serializable)((Object)array));
621                } else if (componentType == Long.TYPE) {
622                    long[] array = new long[length];
623                    in.read_longlong_array(array, 0, length);
624                    return ((java.io.Serializable)((Object)array));
625                } else if (componentType == Float.TYPE) {
626                    float[] array = new float[length];
627                    in.read_float_array(array, 0, length);
628                    return ((java.io.Serializable)((Object)array));
629                } else if (componentType == Double.TYPE) {
630                    double[] array = new double[length];
631                    in.read_double_array(array, 0, length);
632                    return ((java.io.Serializable)((Object)array));
633                } else if (componentType == Short.TYPE) {
634                    short[] array = new short[length];
635                    in.read_short_array(array, 0, length);
636                    return ((java.io.Serializable)((Object)array));
637                } else if (componentType == Character.TYPE) {
638                    char[] array = new char[length];
639                    readCharArray(in, array, 0, length);
640                    return ((java.io.Serializable)((Object)array));
641                } else if (componentType == Boolean.TYPE) {
642                    boolean[] array = new boolean[length];
643                    in.read_boolean_array(array, 0, length);
644                    return ((java.io.Serializable)((Object)array));
645                } else {
646                    // XXX I18N, logging needed.
647                    throw new Error("Invalid primitive componentType : " + sequence.getName());
648                }
649            } else if (componentType == java.lang.Object.class) {
650                Object[] array = (Object[])java.lang.reflect.Array.newInstance(
651                    componentType, length);
652
653                // Store this object and its beginning position
654                // since there might be indirections to it while
655                // it's been unmarshalled.
656                bridge.activeRecursionMgr.addObject(offset, array);
657
658                for (i = 0; i < length; i++) {
659                    Object objectValue = null;
660                    try {
661                        objectValue = Util.readAny(in);
662                    } catch(IndirectionException cdrie) {
663                        try {
664                            // The CDR stream had never seen the given offset
665                            // before, so check the recursion manager (it will
666                            // throw an IOException if it doesn't have a
667                            // reference, either).
668                            objectValue = bridge.activeRecursionMgr.getObject(
669                                cdrie.offset);
670                        } catch (IOException ie) {
671                            // Translate to a MARSHAL exception since
672                            // ValueHandlers aren't allowed to throw
673                            // IOExceptions
674                            throw utilWrapper.invalidIndirection( ie,
675                                new Integer( cdrie.offset ) ) ;
676                        }
677                    }
678
679                    array[i] = objectValue;
680                }
681                return ((java.io.Serializable)((Object)array));
682            } else {
683                Object[] array = (Object[])java.lang.reflect.Array.newInstance(
684                    componentType, length);
685                // Store this object and its beginning position
686                // since there might be indirections to it while
687                // it's been unmarshalled.
688                bridge.activeRecursionMgr.addObject(offset, array);
689
690                // Decide what method call to make based on the componentType.
691                // If it is a componentType for which we need to load a stub,
692                // convert the componentType to the correct stub type.
693
694                int callType = kValueType;
695                boolean narrow = false;
696
697                if (componentType.isInterface()) {
698                    boolean loadStubClass = false;
699                    // String className = componentType.getName();
700
701                    if (java.rmi.Remote.class.isAssignableFrom(componentType)) {
702
703                        // RMI Object reference...
704                        callType = kRemoteType;
705
706                        // for better performance, load the stub class once
707                        // instead of for each element of the array
708                        loadStubClass = true;
709                    } else if (org.omg.CORBA.Object.class.isAssignableFrom(componentType)){
710                        // IDL Object reference...
711                        callType = kRemoteType;
712                        loadStubClass = true;
713                    } else if (RepositoryId.isAbstractBase(componentType)) {
714                        // IDL Abstract Object reference...
715                        callType = kAbstractType;
716                        loadStubClass = true;
717                    } else if (ObjectStreamClassCorbaExt.isAbstractInterface(componentType)) {
718
719                        // RMI Abstract Object reference...
720
721                        // componentType = null;
722                        callType = kAbstractType;
723                    }
724
725                    if (loadStubClass) {
726                        try {
727                            String codebase = Util.getCodebase(componentType);
728                            String repID = RepositoryId.createForAnyType(componentType);
729                            Class stubType =
730                                Utility.loadStubClass(repID, codebase, componentType);
731                            actualType = stubType;
732                        } catch (ClassNotFoundException e) {
733                            narrow = true;
734                        }
735                    } else {
736                        narrow = true;
737                    }
738                }
739
740                for (i = 0; i < length; i++) {
741
742                    try {
743                        switch (callType) {
744                        case kRemoteType:
745                            if (!narrow)
746                                array[i] = (Object)in.read_Object(actualType);
747                            else {
748                                array[i] = Utility.readObjectAndNarrow(in, actualType);
749
750                            }
751                            break;
752                        case kAbstractType:
753                            if (!narrow)
754                                array[i] = (Object)in.read_abstract_interface(actualType);
755                            else {
756                                array[i] = Utility.readAbstractAndNarrow(in, actualType);
757                            }
758                            break;
759                        case kValueType:
760                            array[i] = (Object)in.read_value(actualType);
761                            break;
762                        }
763                    } catch(IndirectionException cdrie) {
764                        // The CDR stream had never seen the given offset before,
765                        // so check the recursion manager (it will throw an
766                        // IOException if it doesn't have a reference, either).
767                        try {
768                            array[i] = bridge.activeRecursionMgr.getObject(
769                                cdrie.offset);
770                        } catch (IOException ioe) {
771                            // Translate to a MARSHAL exception since
772                            // ValueHandlers aren't allowed to throw
773                            // IOExceptions
774                            throw utilWrapper.invalidIndirection( ioe,
775                                new Integer( cdrie.offset ) ) ;
776                        }
777                    }
778
779                }
780
781                return ((java.io.Serializable)((Object)array));
782            }
783        } finally {
784            // We've completed deserializing this object.  Any
785            // future indirections will be handled correctly at the
786            // CDR level.  The ActiveRecursionManager only deals with
787            // objects currently being deserialized.
788            bridge.activeRecursionMgr.removeObject(offset);
789        }
790    }
791
792    private boolean isArray(String repId){
793        return RepositoryId.cache.getId(repId).isSequence();
794    }
795
796    private String getOutputStreamClassName() {
797        return "com.sun.corba.se.impl.io.IIOPOutputStream";
798    }
799
800   private IIOPOutputStream createOutputStream() {
801        final String name = getOutputStreamClassName();
802        try {
803             IIOPOutputStream stream = createOutputStreamBuiltIn(name);
804             if (stream != null) {
805                 return stream;
806             }
807             return createCustom(IIOPOutputStream.class, name);
808        } catch (Throwable t) {
809            // Throw exception under the carpet.
810            InternalError ie = new InternalError(
811                "Error loading " + name
812            );
813                ie.initCause(t);
814                throw ie;
815        }
816    }
817
818    /**
819     * Construct a built in implementation with priveleges.
820     * Returning null indicates a non-built is specified.
821     */
822    private IIOPOutputStream createOutputStreamBuiltIn(
823        final String name
824    ) throws Throwable {
825        try {
826            return AccessController.doPrivileged(
827                new PrivilegedExceptionAction<IIOPOutputStream>() {
828                    public IIOPOutputStream run() throws IOException {
829                        return createOutputStreamBuiltInNoPriv(name);
830                    }
831                }
832            );
833        } catch (java.security.PrivilegedActionException exc) {
834            throw exc.getCause();
835        }
836    }
837
838    /**
839     * Returning null indicates a non-built is specified.
840     */
841    private IIOPOutputStream createOutputStreamBuiltInNoPriv(
842        final String name
843    ) throws IOException {
844        return name.equals(IIOPOutputStream.class.getName()) ?
845                new IIOPOutputStream() : null;
846    }
847
848    private String getInputStreamClassName() {
849        return "com.sun.corba.se.impl.io.IIOPInputStream";
850    }
851
852    private IIOPInputStream createInputStream() {
853        final String name = getInputStreamClassName();
854        try {
855             IIOPInputStream stream = createInputStreamBuiltIn(name);
856             if (stream != null) {
857                 return stream;
858             }
859             return createCustom(IIOPInputStream.class, name);
860        } catch (Throwable t) {
861            // Throw exception under the carpet.
862            InternalError ie = new InternalError(
863                "Error loading " + name
864            );
865                ie.initCause(t);
866                throw ie;
867        }
868    }
869
870    /**
871     * Construct a built in implementation with priveleges.
872     * Returning null indicates a non-built is specified.
873     */
874     private IIOPInputStream createInputStreamBuiltIn(
875         final String name
876     ) throws Throwable {
877         try {
878             return AccessController.doPrivileged(
879                 new PrivilegedExceptionAction<IIOPInputStream>() {
880                     public IIOPInputStream run() throws IOException {
881                         return createInputStreamBuiltInNoPriv(name);
882                     }
883                 }
884             );
885         } catch (java.security.PrivilegedActionException exc) {
886             throw exc.getCause();
887         }
888     }
889
890     /**
891      * Returning null indicates a non-built is specified.
892      */
893     private IIOPInputStream createInputStreamBuiltInNoPriv(
894         final String name
895     ) throws IOException {
896         return name.equals(IIOPInputStream.class.getName()) ?
897                new IIOPInputStream() : null;
898     }
899
900     /**
901      * Create a custom implementation without privileges.
902      */
903     private <T> T createCustom(
904         final Class<T> type, final String className
905     ) throws Throwable {
906           // Note: We use the thread context or system ClassLoader here
907           // since we want to load classes outside of the
908           // core JDK when running J2EE Pure ORB and
909           // talking to Kestrel.
910                ClassLoader cl = Thread.currentThread().getContextClassLoader();
911                if (cl == null)
912                    cl = ClassLoader.getSystemClassLoader();
913
914                Class<?> clazz = cl.loadClass(className);
915                Class<? extends T> streamClass = clazz.asSubclass(type);
916
917                // Since the ClassLoader should cache the class, this isn't
918                // as expensive as it looks.
919                return streamClass.newInstance();
920
921    }
922
923    TCKind getJavaCharTCKind() {
924        return TCKind.tk_wchar;
925    }
926}
927