1 /*
   2  * Copyright (c) 2000, 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.orbutil;
  33 
  34 import java.util.StringTokenizer;
  35 import java.util.Hashtable;
  36 import java.io.IOException;
  37 import java.lang.reflect.Method;
  38 
  39 // Imports for using codebase URL to load class
  40 import java.net.MalformedURLException;
  41 import org.omg.CORBA.portable.ValueBase;
  42 import org.omg.CORBA.portable.IDLEntity;
  43 
  44 import com.sun.corba.se.impl.util.JDKBridge;
  45 import com.sun.corba.se.impl.util.Utility;
  46 import com.sun.corba.se.impl.util.PackagePrefixChecker;
  47 import com.sun.corba.se.impl.util.IdentityHashtable;
  48 import com.sun.corba.se.impl.io.ObjectStreamClass;
  49 
  50 import javax.rmi.CORBA.Util;
  51 
  52 // keeping the original RepositoryId class that was shipped in
  53 // JDK 1.3.  It has interoperability bugs
  54 
  55 public class RepositoryId_1_3 {
  56 
  57     // Legal IDL Identifier characters (1 = legal). Note
  58     // that '.' (2E) is marked as legal even though it is
  59     // not legal in IDL. This allows us to treat a fully
  60     // qualified Java name with '.' package separators
  61     // uniformly, and is safe because that is the only
  62     // legal use of '.' in a Java name.
  63 
  64     public static final RepositoryIdCache_1_3 cache = new RepositoryIdCache_1_3();
  65     private static final byte[] IDL_IDENTIFIER_CHARS = {
  66 
  67         // 0 1 2 3  4 5 6 7  8 9 a b  c d e f
  68         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 00-0f
  69         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 10-1f
  70         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, // 20-2f
  71         1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, // 30-3f
  72         0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 40-4f
  73         1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, // 50-5f
  74         0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 60-6f
  75         1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, // 70-7f
  76         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 80-8f
  77         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 90-9f
  78         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // a0-af
  79         0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // b0-bf
  80         1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // c0-cf
  81         0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // d0-df
  82         1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // e0-ef
  83         0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // f0-ff
  84     };
  85 
  86     private static String defaultServerURL = null;
  87     private static boolean useCodebaseOnly = false;
  88 
  89     static {
  90         if (defaultServerURL == null)
  91             defaultServerURL = (String)JDKBridge.getLocalCodebase();
  92         useCodebaseOnly = JDKBridge.useCodebaseOnly();
  93 
  94     }
  95 
  96     private static IdentityHashtable classToRepStr = new IdentityHashtable();
  97     private static IdentityHashtable classIDLToRepStr = new IdentityHashtable();
  98     private static IdentityHashtable classSeqToRepStr = new IdentityHashtable();
  99 
 100     private static IdentityHashtable repStrToByteArray = new IdentityHashtable();
 101     private static Hashtable repStrToClass = new Hashtable();
 102 
 103     private String repId = null;
 104     private boolean isSupportedFormat = true;
 105     private String typeString = null;
 106     private String versionString = null;
 107     private boolean isSequence = false;
 108     private boolean isRMIValueType = false;
 109     private boolean isIDLType = false;
 110     private String completeClassName = null;
 111     private String unqualifiedName = null;
 112     private String definedInId = null;
 113     private Class clazz = null;
 114     private String suid = null, actualSuid = null;
 115     private long suidLong = ObjectStreamClass.kDefaultUID, actualSuidLong = ObjectStreamClass.kDefaultUID;
 116 
 117     // Repository ID fragments
 118     private static final String kValuePrefix = "RMI:";
 119     private static final String kIDLPrefix = "IDL:";
 120     private static final String kIDLNamePrefix = "omg.org/";
 121     private static final String kIDLClassnamePrefix = "org.omg.";
 122     private static final String kSequencePrefix = "[";
 123     private static final String kCORBAPrefix = "CORBA/";
 124     private static final String kArrayPrefix = kValuePrefix + kSequencePrefix + kCORBAPrefix;
 125     private static final int kValuePrefixLength = kValuePrefix.length();
 126     private static final int kIDLPrefixLength = kIDLPrefix.length();
 127     private static final int kSequencePrefixLength = kSequencePrefix.length();
 128     private static final String kInterfaceHashCode = ":0000000000000000";
 129     private static final String kInterfaceOnlyHashStr = "0000000000000000";
 130     private static final String kExternalizableHashStr = "0000000000000001";
 131 
 132     // Value tag utility methods and constants
 133     public static final int kInitialValueTag= 0x7fffff00;
 134     public static final int kNoTypeInfo = 0;
 135     public static final int kSingleRepTypeInfo = 0x02;
 136     public static final int  kPartialListTypeInfo = 0x06;
 137     public static final int  kChunkedMask = 0x08;
 138 
 139     // Public, well known repository IDs
 140 
 141     // _REVISIT_ : A table structure with a good search routine for all of this
 142     // would be more efficient and easier to maintain...
 143 
 144     // String
 145     public static final String kWStringValueVersion = "1.0";
 146     public static final String kWStringValueHash = ":"+kWStringValueVersion;
 147     public static final String kWStringStubValue = "WStringValue";
 148     public static final String kWStringTypeStr = "omg.org/CORBA/"+kWStringStubValue;
 149     public static final String kWStringValueRepID = kIDLPrefix + kWStringTypeStr + kWStringValueHash;
 150 
 151     // Any
 152     public static final String kAnyRepID = kIDLPrefix + "omg.org/CORBA/Any";
 153 
 154     // Class
 155     public static final String kClassDescValueHash = ":" + Long.toHexString(
 156        ObjectStreamClass.getSerialVersionUID(javax.rmi.CORBA.ClassDesc.class));
 157     public static final String kClassDescStubValue = "ClassDesc";
 158     public static final String kClassDescTypeStr = "javax.rmi.CORBA."+kClassDescStubValue;
 159     public static final String kClassDescValueRepID = kValuePrefix + kClassDescTypeStr + kClassDescValueHash;
 160 
 161     // Object
 162     public static final String kObjectValueHash = ":1.0";
 163     public static final String kObjectStubValue = "Object";
 164 
 165     // Sequence
 166     public static final String kSequenceValueHash = ":1.0";
 167     public static final String kPrimitiveSequenceValueHash = ":0000000000000000";
 168 
 169     // Serializable
 170     public static final String kSerializableValueHash = ":1.0";
 171     public static final String kSerializableStubValue = "Serializable";
 172 
 173     // Externalizable
 174     public static final String kExternalizableValueHash = ":1.0";
 175     public static final String kExternalizableStubValue = "Externalizable";
 176 
 177     // Remote (The empty string is used for java.rmi.Remote)
 178     public static final String kRemoteValueHash = "";
 179     public static final String kRemoteStubValue = "";
 180     public static final String kRemoteTypeStr = "";
 181     public static final String kRemoteValueRepID = "";
 182 
 183     private static final Hashtable kSpecialArrayTypeStrings = new Hashtable();
 184 
 185     static {
 186         kSpecialArrayTypeStrings.put("CORBA.WStringValue", new StringBuffer(java.lang.String.class.getName()));
 187         kSpecialArrayTypeStrings.put("javax.rmi.CORBA.ClassDesc", new StringBuffer(java.lang.Class.class.getName()));
 188         kSpecialArrayTypeStrings.put("CORBA.Object", new StringBuffer(java.rmi.Remote.class.getName()));
 189 
 190     }
 191 
 192     private static final Hashtable kSpecialCasesRepIDs = new Hashtable();
 193 
 194     static {
 195         kSpecialCasesRepIDs.put(java.lang.String.class, kWStringValueRepID);
 196         kSpecialCasesRepIDs.put(java.lang.Class.class, kClassDescValueRepID);
 197         kSpecialCasesRepIDs.put(java.rmi.Remote.class, kRemoteValueRepID);
 198     }
 199 
 200     private static final Hashtable kSpecialCasesStubValues = new Hashtable();
 201 
 202     static {
 203         kSpecialCasesStubValues.put(java.lang.String.class, kWStringStubValue);
 204         kSpecialCasesStubValues.put(java.lang.Class.class, kClassDescStubValue);
 205         kSpecialCasesStubValues.put(java.lang.Object.class, kObjectStubValue);
 206         kSpecialCasesStubValues.put(java.io.Serializable.class, kSerializableStubValue);
 207         kSpecialCasesStubValues.put(java.io.Externalizable.class, kExternalizableStubValue);
 208         kSpecialCasesStubValues.put(java.rmi.Remote.class, kRemoteStubValue);
 209     }
 210 
 211 
 212     private static final Hashtable kSpecialCasesVersions = new Hashtable();
 213 
 214     static {
 215         kSpecialCasesVersions.put(java.lang.String.class, kWStringValueHash);
 216         kSpecialCasesVersions.put(java.lang.Class.class, kClassDescValueHash);
 217         kSpecialCasesVersions.put(java.lang.Object.class, kObjectValueHash);
 218         kSpecialCasesVersions.put(java.io.Serializable.class, kSerializableValueHash);
 219         kSpecialCasesVersions.put(java.io.Externalizable.class, kExternalizableValueHash);
 220         kSpecialCasesVersions.put(java.rmi.Remote.class, kRemoteValueHash);
 221     }
 222 
 223     private static final Hashtable kSpecialCasesClasses = new Hashtable();
 224 
 225     static {
 226         kSpecialCasesClasses.put(kWStringTypeStr, java.lang.String.class);
 227         kSpecialCasesClasses.put(kClassDescTypeStr, java.lang.Class.class);
 228         kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class);
 229 
 230         kSpecialCasesClasses.put("org.omg.CORBA.WStringValue", java.lang.String.class);
 231         kSpecialCasesClasses.put("javax.rmi.CORBA.ClassDesc", java.lang.Class.class);
 232         //kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class);
 233     }
 234 
 235     private static final Hashtable kSpecialCasesArrayPrefix = new Hashtable();
 236 
 237     static {
 238         kSpecialCasesArrayPrefix.put(java.lang.String.class, kValuePrefix + kSequencePrefix + kCORBAPrefix);
 239         kSpecialCasesArrayPrefix.put(java.lang.Class.class, kValuePrefix + kSequencePrefix + "javax/rmi/CORBA/");
 240         kSpecialCasesArrayPrefix.put(java.lang.Object.class, kValuePrefix + kSequencePrefix + "java/lang/");
 241         kSpecialCasesArrayPrefix.put(java.io.Serializable.class, kValuePrefix + kSequencePrefix + "java/io/");
 242         kSpecialCasesArrayPrefix.put(java.io.Externalizable.class, kValuePrefix + kSequencePrefix + "java/io/");
 243         kSpecialCasesArrayPrefix.put(java.rmi.Remote.class, kValuePrefix + kSequencePrefix + kCORBAPrefix);
 244     }
 245 
 246     private static final Hashtable kSpecialPrimitives = new Hashtable();
 247 
 248     static {
 249         kSpecialPrimitives.put("int","long");
 250         kSpecialPrimitives.put("long","longlong");
 251         kSpecialPrimitives.put("byte","octet");
 252     }
 253 
 254     /**
 255      * Used to convert ascii to hex.
 256      */
 257     private static final byte ASCII_HEX[] =     {
 258         (byte)'0',
 259         (byte)'1',
 260         (byte)'2',
 261         (byte)'3',
 262         (byte)'4',
 263         (byte)'5',
 264         (byte)'6',
 265         (byte)'7',
 266         (byte)'8',
 267         (byte)'9',
 268         (byte)'A',
 269         (byte)'B',
 270         (byte)'C',
 271         (byte)'D',
 272         (byte)'E',
 273         (byte)'F',
 274     };
 275 
 276 
 277     // Interface Rep ID Strings
 278     public static final String kjava_rmi_Remote = createForAnyType(java.rmi.Remote.class);
 279     public static final String korg_omg_CORBA_Object = createForAnyType(org.omg.CORBA.Object.class);
 280 
 281     // Dummy arguments for getIdFromHelper method
 282     public static final Class kNoParamTypes[] ={};
 283     public static final Object kNoArgs[] = {};
 284 
 285 
 286     RepositoryId_1_3(){}
 287 
 288     RepositoryId_1_3(String aRepId){
 289         init(aRepId);
 290     }
 291 
 292     RepositoryId_1_3 init(String aRepId){
 293 
 294         this.repId = aRepId;
 295 
 296         // Special case for remote
 297         if (aRepId.length() == 0) {
 298             clazz = java.rmi.Remote.class;
 299             typeString = "";
 300             isRMIValueType = true;
 301             suid = kInterfaceOnlyHashStr;
 302             return this;
 303         }
 304         else if (aRepId.equals(kWStringValueRepID)) {
 305             clazz = java.lang.String.class;
 306             typeString = kWStringTypeStr;
 307             isIDLType = true;
 308             versionString = kWStringValueVersion;
 309             return this;
 310         }
 311         else {
 312 
 313         String repId = convertFromISOLatin1(aRepId);
 314 
 315         versionString = repId.substring(repId.indexOf(':', repId.indexOf(':')+1));
 316         if (repId.startsWith(kIDLPrefix)) {
 317             typeString =
 318                 repId.substring(kIDLPrefixLength, repId.indexOf(':', kIDLPrefixLength));
 319             isIDLType = true;
 320             if (typeString.startsWith(kIDLNamePrefix))
 321                 completeClassName = kIDLClassnamePrefix +
 322                     typeString.substring(kIDLNamePrefix.length()).replace('/','.');
 323             else completeClassName = typeString.replace('/','.');
 324 
 325         }
 326         else if (repId.startsWith(kValuePrefix)) {
 327             typeString =
 328                 repId.substring(kValuePrefixLength, repId.indexOf(':', kValuePrefixLength));
 329             isRMIValueType = true;
 330 
 331             if (versionString.indexOf('.') == -1) {
 332                     actualSuid = versionString.substring(1);
 333                     suid = actualSuid;  // default if not explicitly specified
 334 
 335                     if (actualSuid.indexOf(':') != -1){
 336                     // we have a declared hash also
 337                         int pos = actualSuid.indexOf(':')+1;
 338                         // actualSuid = suid.substring(pos);
 339                         // suid = suid.substring(0, pos-1);
 340                         suid = actualSuid.substring(pos);
 341                         actualSuid = actualSuid.substring(0, pos-1);
 342                 }
 343 
 344             }
 345             else {
 346                     // _REVISIT_ : Special case version failure ?
 347             }
 348         }
 349         else isSupportedFormat = false;
 350 
 351         if (typeString.startsWith(kSequencePrefix)) {
 352             isSequence = true;
 353         }
 354 
 355 
 356         return this;
 357     }
 358     }
 359 
 360     public final String getUnqualifiedName() {
 361         if (unqualifiedName == null){
 362             String className = getClassName();
 363             int index = (className != null) ? className.lastIndexOf('.') : -1;
 364             if (index == -1){
 365                 unqualifiedName = className;
 366                 definedInId = "IDL::1.0";
 367             }
 368             else {
 369                 unqualifiedName = className.substring(index);
 370                 definedInId = "IDL:" + className.substring(0, index).replace('.','/') + ":1.0";
 371             }
 372         }
 373 
 374         return unqualifiedName;
 375     }
 376 
 377     public final String getDefinedInId() {
 378         if (definedInId == null){
 379             getUnqualifiedName();
 380         }
 381 
 382         return definedInId;
 383     }
 384 
 385     public final String getTypeString() {
 386         return typeString;
 387     }
 388 
 389     public final String getVersionString() {
 390         return versionString;
 391     }
 392 
 393     public final String getSerialVersionUID() {
 394         return suid;
 395     }
 396 
 397     public final String getActualSerialVersionUID() {
 398         return actualSuid;
 399     }
 400     public final long getSerialVersionUIDAsLong() {
 401         return suidLong;
 402     }
 403 
 404     public final long getActualSerialVersionUIDAsLong() {
 405         return actualSuidLong;
 406     }
 407 
 408     public final boolean isRMIValueType() {
 409         return isRMIValueType;
 410     }
 411 
 412     public final boolean isIDLType() {
 413         return isIDLType;
 414     }
 415 
 416     public final String getRepositoryId() {
 417         return repId;
 418     }
 419 
 420     public static byte[] getByteArray(String repStr) {
 421         synchronized (repStrToByteArray){
 422             return (byte[]) repStrToByteArray.get(repStr);
 423         }
 424     }
 425 
 426     public static void setByteArray(String repStr, byte[] repStrBytes) {
 427         synchronized (repStrToByteArray){
 428             repStrToByteArray.put(repStr, repStrBytes);
 429         }
 430     }
 431 
 432     public final boolean isSequence() {
 433         return isSequence;
 434     }
 435 
 436     public final boolean isSupportedFormat() {
 437         return isSupportedFormat;
 438     }
 439 
 440 
 441     // This method will return the classname from the typestring OR if the classname turns out to be
 442     // a special class "pseudo" name, then the matching real classname is returned.
 443     public final String getClassName() {
 444 
 445         if (isRMIValueType)
 446             return typeString;
 447         else if (isIDLType)
 448             return completeClassName;
 449         else return null;
 450 
 451     }
 452 
 453     // This method calls getClazzFromType() and falls back to the repStrToClass
 454     // cache if no class was found.  It's used where any class matching the
 455     // given repid is an acceptable result.
 456     public final Class getAnyClassFromType() throws ClassNotFoundException {
 457         try {
 458             return getClassFromType();
 459         } catch (ClassNotFoundException cnfe) {
 460             Class clz = (Class)repStrToClass.get(repId);
 461             if (clz != null)
 462                 return clz;
 463             else
 464                 throw cnfe;
 465         }
 466     }
 467 
 468     public final Class getClassFromType()
 469         throws ClassNotFoundException {
 470         if (clazz != null)
 471             return clazz;
 472 
 473         Class specialCase = (Class)kSpecialCasesClasses.get(getClassName());
 474 
 475         if (specialCase != null){
 476             clazz = specialCase;
 477             return specialCase;
 478         }
 479         else
 480             {
 481                 try{
 482                     return Util.loadClass(getClassName(), null, null);
 483                 }
 484                 catch(ClassNotFoundException cnfe){
 485                     if (defaultServerURL != null) {
 486                         try{
 487                             return getClassFromType(defaultServerURL);
 488                         }
 489                         catch(MalformedURLException mue){
 490                             throw cnfe;
 491                         }
 492                     }
 493                     else throw cnfe;
 494                 }
 495             }
 496 
 497     }
 498 
 499     public final Class getClassFromType(Class expectedType, String codebase)
 500         throws ClassNotFoundException {
 501         if (clazz != null)
 502             return clazz;
 503 
 504         Class specialCase = (Class)kSpecialCasesClasses.get(getClassName());
 505 
 506         if (specialCase != null){
 507             clazz = specialCase;
 508             return specialCase;
 509         } else {
 510             ClassLoader expectedTypeClassLoader = (expectedType == null ? null : expectedType.getClassLoader());
 511             return loadClassOfType(getClassName(),
 512                                             codebase,
 513                                             expectedTypeClassLoader,
 514                                             expectedType,
 515                                             expectedTypeClassLoader);
 516         }
 517 
 518     }
 519 
 520     public final Class getClassFromType(String url)
 521         throws ClassNotFoundException, MalformedURLException {
 522         return Util.loadClass(getClassName(), url, null);
 523     }
 524 
 525     public final String toString() {
 526         return repId;
 527     }
 528 
 529     private static String createHashString(java.io.Serializable ser) {
 530 
 531         return createHashString(ser.getClass());
 532     }
 533 
 534     private static String createHashString(java.lang.Class clazz) {
 535 
 536         if (clazz.isInterface() || !java.io.Serializable.class.isAssignableFrom(clazz))
 537             return kInterfaceHashCode;
 538 
 539 
 540         long actualLong = ObjectStreamClassUtil_1_3.computeStructuralUID(false, clazz);
 541         String hash = null;
 542         if (actualLong == 0)
 543             hash = kInterfaceOnlyHashStr;
 544         else if (actualLong == 1)
 545             hash = kExternalizableHashStr;
 546         else
 547             hash = Long.toHexString(actualLong).toUpperCase();
 548         while(hash.length() < 16){
 549             hash = "0" + hash;
 550         }
 551 
 552         long declaredLong = ObjectStreamClassUtil_1_3.computeSerialVersionUID(clazz);
 553         String declared = null;
 554         if (declaredLong == 0)
 555             declared = kInterfaceOnlyHashStr;
 556         else if (declaredLong == 1)
 557             declared = kExternalizableHashStr;
 558         else
 559             declared = Long.toHexString(declaredLong).toUpperCase();
 560         while (declared.length() < 16){
 561             declared = "0" + declared;
 562     }
 563         hash = hash + ":" + declared;
 564 
 565         return ":" + hash;
 566     }
 567 
 568     /**
 569      * Creates a repository ID for a sequence.  This is for expert users only as
 570      * this method assumes the object passed is an array.  If passed an object
 571      * that is not an array, it will produce a rep id for a sequence of zero
 572      * length.  This would be an error.
 573      * @param ser The Java object to create a repository ID for
 574      **/
 575     public static String createSequenceRepID(java.lang.Object ser){
 576         return createSequenceRepID(ser.getClass());
 577     }
 578 
 579     /**
 580      * Creates a repository ID for a sequence.  This is for expert users only as
 581      * this method assumes the object passed is an array.  If passed an object
 582      * that is not an array, it will produce a malformed rep id.
 583      * @param clazz The Java class to create a repository ID for
 584      **/
 585     public static String createSequenceRepID(java.lang.Class clazz){
 586         synchronized (classSeqToRepStr){
 587 
 588         String repid = (String)classSeqToRepStr.get(clazz);
 589         if (repid != null)
 590             return repid;
 591 
 592         Class originalClazz = clazz;
 593 
 594         Class type = null;
 595         int numOfDims = 0;
 596 
 597         while ((type = clazz.getComponentType()) != null) {
 598             numOfDims++;
 599             clazz = type;
 600         }
 601 
 602         if (clazz.isPrimitive())
 603             repid = kValuePrefix + originalClazz.getName() + kPrimitiveSequenceValueHash;
 604         else {
 605             StringBuffer buf = new StringBuffer();
 606             buf.append(kValuePrefix);
 607             while(numOfDims-- > 0) {
 608                 buf.append("[");
 609             }
 610             buf.append("L");
 611             buf.append(convertToISOLatin1(clazz.getName()));
 612             buf.append(";");
 613             buf.append(createHashString(clazz));
 614             repid = buf.toString();
 615         }
 616         classSeqToRepStr.put(originalClazz,repid);
 617         return repid;
 618         }
 619 
 620     }
 621 
 622 
 623     public static String createForSpecialCase(java.lang.Class clazz){
 624         if (clazz.isArray()){
 625             return createSequenceRepID(clazz);
 626         }
 627         else {
 628             return (String)kSpecialCasesRepIDs.get(clazz);
 629         }
 630     }
 631 
 632     public static String createForSpecialCase(java.io.Serializable ser){
 633         Class clazz = ser.getClass();
 634         if (clazz.isArray()){
 635             return createSequenceRepID(ser);
 636         }
 637         else
 638             return createForSpecialCase(clazz);
 639     }
 640 
 641     /**
 642      * Creates a repository ID for a normal Java Type.
 643      * @param ser The Java object to create a repository ID for
 644      * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the
 645      * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type.
 646      **/
 647     public static String createForJavaType(java.io.Serializable ser)
 648         throws com.sun.corba.se.impl.io.TypeMismatchException
 649     {
 650         synchronized (classToRepStr) {
 651         String repid = createForSpecialCase(ser);
 652         if (repid != null)
 653             return repid;
 654         Class clazz = ser.getClass();
 655         repid = (String)classToRepStr.get(clazz);
 656 
 657         if (repid != null)
 658             return repid;
 659 
 660         repid = kValuePrefix + convertToISOLatin1(clazz.getName()) +
 661             createHashString(clazz);
 662 
 663         classToRepStr.put(clazz, repid);
 664             repStrToClass.put(repid, clazz);
 665         return repid;
 666     }
 667     }
 668 
 669     /**
 670      * Creates a repository ID for a normal Java Type.
 671      * @param clz The Java class to create a repository ID for
 672      * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the
 673      * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type.
 674      **/
 675     public static String createForJavaType(Class clz)
 676         throws com.sun.corba.se.impl.io.TypeMismatchException
 677     {
 678         synchronized (classToRepStr){
 679         String repid = createForSpecialCase(clz);
 680         if (repid != null)
 681             return repid;
 682 
 683         repid = (String)classToRepStr.get(clz);
 684         if (repid != null)
 685             return repid;
 686 
 687         repid = kValuePrefix + convertToISOLatin1(clz.getName()) +
 688             createHashString(clz);
 689 
 690         classToRepStr.put(clz, repid);
 691             repStrToClass.put(repid, clz);
 692         return repid;
 693     }
 694     }
 695 
 696     /**
 697      * Creates a repository ID for an IDL Java Type.
 698      * @param ser The IDL Value object to create a repository ID for
 699      * @param major The major version number
 700      * @param minor The minor version number
 701      * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser does not implement the
 702      * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type.
 703      **/
 704     public static String createForIDLType(Class ser, int major, int minor)
 705         throws com.sun.corba.se.impl.io.TypeMismatchException
 706     {
 707         synchronized (classIDLToRepStr){
 708         String repid = (String)classIDLToRepStr.get(ser);
 709         if (repid != null)
 710             return repid;
 711 
 712         repid = kIDLPrefix + convertToISOLatin1(ser.getName()).replace('.','/') +
 713             ":" + major + "." + minor;
 714         classIDLToRepStr.put(ser, repid);
 715         return repid;
 716     }
 717     }
 718 
 719     private static String getIdFromHelper(Class clazz){
 720         try {
 721             Class helperClazz = Utility.loadClassForClass(clazz.getName()+"Helper", null,
 722                                     clazz.getClassLoader(), clazz, clazz.getClassLoader());
 723             Method idMethod = helperClazz.getDeclaredMethod("id", kNoParamTypes);
 724             return (String)idMethod.invoke(null, kNoArgs);
 725         }
 726         catch(java.lang.ClassNotFoundException cnfe)
 727             {
 728                 throw new org.omg.CORBA.MARSHAL(cnfe.toString());
 729             }
 730         catch(java.lang.NoSuchMethodException nsme)
 731             {
 732                 throw new org.omg.CORBA.MARSHAL(nsme.toString());
 733             }
 734         catch(java.lang.reflect.InvocationTargetException ite)
 735             {
 736                 throw new org.omg.CORBA.MARSHAL(ite.toString());
 737             }
 738         catch(java.lang.IllegalAccessException iae)
 739             {
 740                 throw new org.omg.CORBA.MARSHAL(iae.toString());
 741     }
 742     }
 743 
 744     /**
 745      * Createa a repository ID for the type if it is either a java type
 746      * or an IDL type.
 747      * @param type The type to create rep. id for
 748      * @return The rep. id.
 749      **/
 750     public static String createForAnyType(Class type) {
 751         try{
 752             if (type.isArray())
 753                 return createSequenceRepID(type);
 754             else if (IDLEntity.class.isAssignableFrom(type))
 755                 {
 756                     try{
 757                         return getIdFromHelper(type);
 758                     }
 759                     catch(Throwable t) {
 760                         return createForIDLType(type, 1, 0);
 761                     }
 762                 }
 763             else return createForJavaType(type);
 764         }
 765         catch(com.sun.corba.se.impl.io.TypeMismatchException e){
 766             return null;
 767         }
 768 
 769     }
 770 
 771     public static boolean isAbstractBase(Class clazz) {
 772         return (clazz.isInterface() &&
 773                 IDLEntity.class.isAssignableFrom(clazz) &&
 774                 (!ValueBase.class.isAssignableFrom(clazz)) &&
 775                 (!org.omg.CORBA.Object.class.isAssignableFrom(clazz)));
 776 
 777     }
 778 
 779     /**
 780      * Convert strings with illegal IDL identifier characters.
 781      * <p>
 782      * Section 5.5.7 of OBV spec.
 783      */
 784     private static String convertToISOLatin1 (String name) {
 785 
 786         int length = name.length();
 787         if (length == 0) {
 788             return name;
 789         }
 790         StringBuffer buffer = null;
 791 
 792         for (int i = 0; i < length; i++) {
 793 
 794             char c = name.charAt(i);
 795 
 796             if (c > 255 || IDL_IDENTIFIER_CHARS[c] == 0) {
 797 
 798                 // We gotta convert. Have we already started?
 799 
 800                 if (buffer == null) {
 801 
 802                     // No, so get set up...
 803 
 804                     buffer = new StringBuffer(name.substring(0,i));
 805                 }
 806 
 807                 // Convert the character into the IDL escape syntax...
 808                 buffer.append(
 809                               "\\U" +
 810                               (char)ASCII_HEX[(c & 0xF000) >>> 12] +
 811                               (char)ASCII_HEX[(c & 0x0F00) >>> 8] +
 812                               (char)ASCII_HEX[(c & 0x00F0) >>> 4] +
 813                               (char)ASCII_HEX[(c & 0x000F)]);
 814 
 815             } else {
 816                 if (buffer != null) {
 817                     buffer.append(c);
 818                 }
 819             }
 820         }
 821 
 822         if (buffer != null) {
 823             name = buffer.toString();
 824         }
 825 
 826         return name;
 827     }
 828 
 829     /**
 830      * Convert strings with ISO Latin 1 escape sequences back to original strings.
 831      * <p>
 832      * Section 5.5.7 of OBV spec.
 833      */
 834     private static String convertFromISOLatin1 (String name) {
 835 
 836         int index = -1;
 837         StringBuffer buf = new StringBuffer(name);
 838 
 839         while ((index = buf.toString().indexOf("\\U")) != -1){
 840             String str = "0000" + buf.toString().substring(index+2, index+6);
 841 
 842             // Convert Hexadecimal
 843             byte[] buffer = new byte[(str.length() - 4) / 2];
 844             for (int i=4, j=0; i < str.length(); i +=2, j++) {
 845                 buffer[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << 4) & 0xF0);
 846                 buffer[j] |= (byte)((ORBUtility.hexOf(str.charAt(i+1)) << 0) & 0x0F);
 847             }
 848             buf = new StringBuffer(delete(buf.toString(), index, index+6));
 849             buf.insert(index, (char)buffer[1]);
 850         }
 851 
 852         return buf.toString();
 853 
 854 
 855     }
 856 
 857     private static String delete(String str, int from, int to)
 858     {
 859         return str.substring(0, from) + str.substring(to, str.length());
 860     }
 861 
 862     private static String replace(String target, String arg, String source)
 863     {
 864         int i = 0;
 865         i = target.indexOf(arg);
 866 
 867         while(i != -1)
 868             {
 869                 String left = target.substring(0, i);
 870                 String right = target.substring(i+arg.length());
 871                 target = new String(left+source+right);
 872                 i = target.indexOf(arg);
 873             }
 874         return target;
 875     }
 876 
 877     /*
 878      * Load a class and check that it is assignable to a given type.
 879      * @param className the class name.
 880      * @param remoteCodebase the codebase to use. May be null.
 881      * @param loader the class loader of last resort. May be null.
 882      * @param expectedType the expected type. May be null.
 883      * @return the loaded class.
 884      */
 885     private Class loadClassOfType (String className,
 886                                   String remoteCodebase,
 887                                   ClassLoader loader,
 888                                   Class expectedType,
 889                                   ClassLoader expectedTypeClassLoader)
 890         throws ClassNotFoundException {
 891 
 892         Class loadedClass = null;
 893 
 894         try {
 895             //Sequence finding of the stubs according to spec
 896             try{
 897                 //If-else is put here for speed up of J2EE.
 898                 //According to the OMG spec, the if clause is not dead code.
 899                 //It can occur if some compiler has allowed generation
 900                 //into org.omg.stub hierarchy for non-offending
 901                 //classes. This will encourage people to
 902                 //produce non-offending class stubs in their own hierarchy.
 903                 if(!PackagePrefixChecker
 904                    .hasOffendingPrefix(PackagePrefixChecker
 905                                        .withoutPackagePrefix(className))){
 906                     loadedClass = Util.loadClass
 907                         (PackagePrefixChecker.withoutPackagePrefix(className),
 908                          remoteCodebase,
 909                          loader);
 910                 } else {
 911                     loadedClass = Util.loadClass
 912                         (className,
 913                          remoteCodebase,
 914                          loader);
 915                 }
 916             } catch (ClassNotFoundException cnfe) {
 917                 loadedClass = Util.loadClass
 918                     (className,
 919                      remoteCodebase,
 920                      loader);
 921             }
 922             if (expectedType == null)
 923                 return loadedClass;
 924         } catch (ClassNotFoundException cnfe) {
 925             if (expectedType == null)
 926                 throw cnfe;
 927         }
 928 
 929         // If no class was not loaded, or if the loaded class is not of the
 930         // correct type, make a further attempt to load the correct class
 931         // using the classloader of the expected type.
 932         // _REVISIT_ Is this step necessary, or should the Util,loadClass
 933         // algorithm always produce a valid class if the setup is correct?
 934         // Does the OMG standard algorithm need to be changed to include
 935         // this step?
 936         if (loadedClass == null || !expectedType.isAssignableFrom(loadedClass)) {
 937             if (expectedType.getClassLoader() != expectedTypeClassLoader)
 938                 throw new IllegalArgumentException("expectedTypeClassLoader not class loader of expectedType.");
 939 
 940             if (expectedTypeClassLoader != null)
 941                 loadedClass = expectedTypeClassLoader.loadClass(className);
 942             else
 943                 loadedClass = ORBClassLoader.loadClass(className);
 944         }
 945 
 946         return loadedClass;
 947     }
 948 
 949     /**
 950      * Checks to see if the FullValueDescription should be retrieved.
 951      * @exception Throws IOException if suids do not match or if the repositoryID
 952      * is not an RMIValueType
 953      */
 954     public static boolean useFullValueDescription(Class clazz, String repositoryID)
 955         throws IOException{
 956 
 957         String clazzRepIDStr = createForAnyType(clazz);
 958 
 959         if (clazzRepIDStr.equals(repositoryID))
 960             return false;
 961 
 962         RepositoryId_1_3 targetRepid;
 963         RepositoryId_1_3 clazzRepid;
 964 
 965         synchronized(cache) {
 966         // to avoid race condition where multiple threads could be
 967         // accessing this method, and their access to the cache may
 968         // be interleaved giving unexpected results
 969 
 970             targetRepid = cache.getId(repositoryID);
 971             clazzRepid = cache.getId(clazzRepIDStr);
 972         }
 973 
 974         if ((targetRepid.isRMIValueType()) && (clazzRepid.isRMIValueType())){
 975             if (!targetRepid.getSerialVersionUID().equals(clazzRepid.getSerialVersionUID())) {
 976 
 977                 String mssg = "Mismatched serialization UIDs : Source (Rep. ID" +
 978                     clazzRepid + ") = " +
 979                     clazzRepid.getSerialVersionUID() + " whereas Target (Rep. ID " + repositoryID +
 980                     ") = " + targetRepid.getSerialVersionUID();
 981                 throw new IOException(mssg);
 982             } else {
 983                 return true;
 984             }
 985         } else {
 986 
 987             throw new IOException("The repository ID is not of an RMI value type (Expected ID = " + clazzRepIDStr + "; Received ID = " + repositoryID +")");
 988         }
 989     }
 990 }