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 
  32 package com.sun.corba.se.impl.io;
  33 
  34 import javax.rmi.CORBA.Util;
  35 
  36 import java.util.Hashtable;
  37 import java.io.IOException;
  38 
  39 import com.sun.corba.se.impl.util.RepositoryId;
  40 import com.sun.corba.se.impl.util.Utility;
  41 
  42 import org.omg.CORBA.TCKind;
  43 
  44 import org.omg.CORBA.portable.IndirectionException;
  45 import com.sun.org.omg.SendingContext.CodeBase;
  46 import com.sun.org.omg.SendingContext.CodeBaseHelper;
  47 
  48 import java.security.AccessController;
  49 import java.security.PrivilegedAction;
  50 import java.security.PrivilegedExceptionAction;
  51 
  52 import com.sun.corba.se.spi.logging.CORBALogDomains;
  53 import com.sun.corba.se.impl.logging.OMGSystemException;
  54 import com.sun.corba.se.impl.logging.UtilSystemException;
  55 
  56 public 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 }