1 /*
   2  * Copyright (c) 1999, 2004, 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 /*
  27  * Licensed Materials - Property of IBM
  28  * RMI-IIOP v1.0
  29  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  30  *
  31  */
  32 
  33 package com.sun.corba.se.impl.util;
  34 
  35 import org.omg.CORBA.SystemException;
  36 import org.omg.CORBA.CompletionStatus;
  37 import org.omg.CORBA.BAD_OPERATION;
  38 import org.omg.CORBA.BAD_INV_ORDER;
  39 import org.omg.CORBA.BAD_PARAM;
  40 import org.omg.CORBA.ORB;
  41 import org.omg.CORBA.Any;
  42 import org.omg.CORBA.TypeCode;
  43 import org.omg.CORBA.Principal;
  44 import org.omg.CORBA.portable.InputStream;
  45 import org.omg.CORBA.portable.OutputStream;
  46 import org.omg.CORBA.portable.BoxedValueHelper;
  47 import org.omg.CORBA.portable.ValueFactory;
  48 import org.omg.CORBA.portable.Streamable;
  49 import org.omg.CORBA.portable.Delegate;
  50 
  51 
  52 import java.util.Hashtable;
  53 import java.util.NoSuchElementException;
  54 
  55 import java.rmi.Remote;
  56 import java.rmi.NoSuchObjectException;
  57 import java.rmi.RemoteException;
  58 import java.rmi.server.RemoteStub;
  59 
  60 import javax.rmi.PortableRemoteObject;
  61 import javax.rmi.CORBA.Stub;
  62 import javax.rmi.CORBA.Tie;
  63 import javax.rmi.CORBA.Util;
  64 
  65 import java.io.Serializable;
  66 import java.io.File;
  67 import java.io.FileInputStream;
  68 
  69 import org.omg.PortableServer.POA;
  70 
  71 import com.sun.org.omg.SendingContext.CodeBase;
  72 
  73 import com.sun.corba.se.spi.logging.CORBALogDomains ;
  74 import com.sun.corba.se.spi.presentation.rmi.PresentationManager;
  75 import com.sun.corba.se.spi.presentation.rmi.StubAdapter ;
  76 
  77 import com.sun.corba.se.impl.logging.UtilSystemException ;
  78 import com.sun.corba.se.impl.logging.OMGSystemException ;
  79 
  80 /**
  81  *  Handy class full of static functions.
  82  */
  83 public final class Utility {
  84 
  85     public static final String STUB_PREFIX = "_";
  86     public static final String RMI_STUB_SUFFIX = "_Stub";
  87     public static final String DYNAMIC_STUB_SUFFIX = "_DynamicStub" ;
  88     public static final String IDL_STUB_SUFFIX = "Stub";
  89     public static final String TIE_SUFIX = "_Tie";
  90     private static IdentityHashtable tieCache = new IdentityHashtable();
  91     private static IdentityHashtable tieToStubCache = new IdentityHashtable();
  92     private static IdentityHashtable stubToTieCache = new IdentityHashtable();
  93     private static Object CACHE_MISS = new Object();
  94     private static UtilSystemException wrapper = UtilSystemException.get(
  95         CORBALogDomains.UTIL ) ;
  96     private static OMGSystemException omgWrapper = OMGSystemException.get(
  97         CORBALogDomains.UTIL ) ;
  98 
  99     /**
 100      * Ensure that stubs, ties, and implementation objects
 101      * are 'connected' to the runtime. Converts implementation
 102      * objects to a type suitable for sending on the wire.
 103      * @param obj the object to connect.
 104      * @param orb the ORB to connect to if obj is exported to IIOP.
 105      * @param convertToStub true if implementation types should be
 106      * converted to Stubs rather than just org.omg.CORBA.Object.
 107      * @return the connected object.
 108      * @exception NoSuchObjectException if obj is an implementation
 109      * which has not been exported.
 110      */
 111     public static Object autoConnect(Object obj, ORB orb, boolean convertToStub)
 112     {
 113         if (obj == null) {
 114             return obj;
 115         }
 116 
 117         if (StubAdapter.isStub(obj)) {
 118             try {
 119                 StubAdapter.getDelegate(obj) ;
 120             } catch (BAD_OPERATION okay) {
 121                 try {
 122                     StubAdapter.connect( obj, orb ) ;
 123                 } catch (RemoteException e) {
 124                     // The stub could not be connected because it
 125                     // has an invalid IOR...
 126                     throw wrapper.objectNotConnected( e,
 127                         obj.getClass().getName() ) ;
 128                 }
 129             }
 130 
 131             return obj;
 132         }
 133 
 134         if (obj instanceof Remote) {
 135             Remote remoteObj = (Remote)obj;
 136             Tie theTie = Util.getTie(remoteObj);
 137             if (theTie != null) {
 138                 try {
 139                     theTie.orb();
 140                 } catch (SystemException okay) {
 141                     theTie.orb(orb);
 142                 }
 143 
 144                 if (convertToStub) {
 145                     Object result = loadStub(theTie,null,null,true);
 146                     if (result != null) {
 147                         return result;
 148                     } else {
 149                         throw wrapper.couldNotLoadStub(obj.getClass().getName());
 150                     }
 151                 } else {
 152                     return StubAdapter.activateTie( theTie );
 153                 }
 154             } else {
 155                 // This is an implementation object which has not been
 156                 // exported to IIOP OR is a JRMP stub or implementation
 157                 // object which cannot be marshalled into an ORB stream...
 158                 throw wrapper.objectNotExported( obj.getClass().getName() ) ;
 159             }
 160         }
 161 
 162         // Didn't need to do anything, just return the input...
 163 
 164         return obj;
 165     }
 166 
 167     /*
 168      * Get a new instance of an RMI-IIOP Tie for the
 169      * given server object.
 170      */
 171     public static Tie loadTie(Remote obj) {
 172         Tie result = null;
 173         Class objClass = obj.getClass();
 174 
 175         // Have we tried to find this guy before?
 176 
 177         synchronized (tieCache) {
 178 
 179             Object it = tieCache.get(obj);
 180 
 181             if (it == null) {
 182 
 183                 // No, so try it...
 184 
 185                 try {
 186 
 187                     // First try the classname...
 188 
 189                     result = loadTie(objClass);
 190 
 191                     // If we don't have a valid tie at this point,
 192                     // walk up the parent chain until we either
 193                     // load a tie or encounter PortableRemoteObject
 194                     // or java.lang.Object...
 195 
 196                     while (result == null &&
 197                            (objClass = objClass.getSuperclass()) != null &&
 198                            objClass != PortableRemoteObject.class &&
 199                            objClass != Object.class) {
 200 
 201                         result = loadTie(objClass);
 202                     }
 203                 } catch (Exception ex) {
 204                     wrapper.loadTieFailed( ex, objClass.getName() ) ;
 205                 }
 206 
 207                 // Did we get it?
 208 
 209                 if (result == null) {
 210 
 211                     // Nope, so cache that fact...
 212 
 213                     tieCache.put(obj,CACHE_MISS);
 214 
 215                 } else {
 216 
 217                     // Yes, so cache it...
 218 
 219                     tieCache.put(obj,result);
 220                 }
 221             } else {
 222 
 223                 // Yes, return a new instance or fail again if
 224                 // it was a miss last time...
 225 
 226                 if (it != CACHE_MISS) {
 227                     try {
 228                         result = (Tie) it.getClass().newInstance();
 229                     } catch (Exception e) {
 230                     }
 231                 }
 232             }
 233         }
 234 
 235         return result;
 236     }
 237 
 238     /*
 239      * Load an RMI-IIOP Tie
 240      */
 241     private static Tie loadTie(Class theClass)
 242     {
 243         return com.sun.corba.se.spi.orb.ORB.getStubFactoryFactory().
 244             getTie( theClass ) ;
 245     }
 246 
 247     /*
 248      * Clear the stub/tie caches. Intended for use by
 249      * test code.
 250      */
 251     public static void clearCaches() {
 252         synchronized (tieToStubCache) {
 253             tieToStubCache.clear();
 254         }
 255         synchronized (tieCache) {
 256             tieCache.clear();
 257         }
 258         synchronized (stubToTieCache) {
 259             stubToTieCache.clear();
 260         }
 261     }
 262 
 263     /*
 264      * Load a class and check that it is assignable to a given type.
 265      * @param className the class name.
 266      * @param remoteCodebase the codebase to use. May be null.
 267      * @param loader the class loader of last resort. May be null.
 268      * @param expectedType the expected type. May be null.
 269      * @return the loaded class.
 270      */
 271     static Class loadClassOfType(String className, String remoteCodebase,
 272         ClassLoader loader, Class expectedType,
 273         ClassLoader expectedTypeClassLoader) throws ClassNotFoundException
 274     {
 275         Class loadedClass = null;
 276 
 277         try {
 278             //Sequence finding of the stubs according to spec
 279             try{
 280                 //If-else is put here for speed up of J2EE.
 281                 //According to the OMG spec, the if clause is not dead code.
 282                 //It can occur if some compiler has allowed generation
 283                 //into org.omg.stub hierarchy for non-offending
 284                 //classes. This will encourage people to
 285                 //produce non-offending class stubs in their own hierarchy.
 286                 if (!PackagePrefixChecker.hasOffendingPrefix(
 287                     PackagePrefixChecker.withoutPackagePrefix(className))){
 288                     loadedClass = Util.loadClass(
 289                         PackagePrefixChecker.withoutPackagePrefix(className),
 290                         remoteCodebase,
 291                         loader);
 292                 } else {
 293                     loadedClass = Util.loadClass(className, remoteCodebase,
 294                         loader);
 295                 }
 296             } catch (ClassNotFoundException cnfe) {
 297                 loadedClass = Util.loadClass(className, remoteCodebase,
 298                     loader);
 299             }
 300             if (expectedType == null)
 301                 return loadedClass;
 302         } catch (ClassNotFoundException cnfe) {
 303             if (expectedType == null)
 304                 throw cnfe;
 305         }
 306 
 307         // If no class was loaded, or if the loaded class is not of the
 308         // correct type, make a further attempt to load the correct class
 309         // using the classloader of the expected type.
 310         // _REVISIT_ Is this step necessary, or should the Util,loadClass
 311         // algorithm always produce a valid class if the setup is correct?
 312         // Does the OMG standard algorithm need to be changed to include
 313         // this step?
 314         if (loadedClass == null || !expectedType.isAssignableFrom(loadedClass)){
 315             if (expectedType.getClassLoader() != expectedTypeClassLoader)
 316                 throw new IllegalArgumentException(
 317                     "expectedTypeClassLoader not class loader of "  +
 318                     "expected Type.");
 319 
 320             if (expectedTypeClassLoader != null)
 321                 loadedClass = expectedTypeClassLoader.loadClass(className);
 322             else {
 323                 ClassLoader cl = Thread.currentThread().getContextClassLoader();
 324                 if (cl == null)
 325                     cl = ClassLoader.getSystemClassLoader();
 326 
 327                 loadedClass = cl.loadClass(className);
 328             }
 329         }
 330 
 331         return loadedClass;
 332     }
 333 
 334     /*
 335      * Load a class and check that it is compatible with a given type.
 336      * @param className the class name.
 337      * @param remoteCodebase the codebase to use. May be null.
 338      * @param loadingContext the loading context. May be null.
 339      * @param relatedType the related type. May be null.
 340      * @return the loaded class.
 341      */
 342     public static Class loadClassForClass (String className,
 343                                            String remoteCodebase,
 344                                            ClassLoader loader,
 345                                            Class relatedType,
 346                                            ClassLoader relatedTypeClassLoader)
 347         throws ClassNotFoundException
 348     {
 349         if (relatedType == null)
 350             return Util.loadClass(className, remoteCodebase, loader);
 351 
 352         Class loadedClass = null;
 353         try {
 354             loadedClass = Util.loadClass(className, remoteCodebase, loader);
 355         } catch (ClassNotFoundException cnfe) {
 356             if (relatedType.getClassLoader() == null)
 357                 throw cnfe;
 358         }
 359 
 360         // If no class was not loaded, or if the loaded class is not of the
 361         // correct type, make a further attempt to load the correct class
 362         // using the classloader of the related type.
 363         // _REVISIT_ Is this step necessary, or should the Util,loadClass
 364         // algorithm always produce a valid class if the setup is correct?
 365         // Does the OMG standard algorithm need to be changed to include
 366         // this step?
 367         if (loadedClass == null ||
 368             (loadedClass.getClassLoader() != null &&
 369              loadedClass.getClassLoader().loadClass(relatedType.getName()) !=
 370                  relatedType))
 371         {
 372             if (relatedType.getClassLoader() != relatedTypeClassLoader)
 373                 throw new IllegalArgumentException(
 374                     "relatedTypeClassLoader not class loader of relatedType.");
 375 
 376             if (relatedTypeClassLoader != null)
 377                 loadedClass = relatedTypeClassLoader.loadClass(className);
 378         }
 379 
 380         return loadedClass;
 381     }
 382 
 383     /**
 384      * Get the helper for an IDLValue
 385      *
 386      * Throws MARSHAL exception if no helper found.
 387      */
 388     public static BoxedValueHelper getHelper(Class clazz, String codebase,
 389         String repId)
 390     {
 391         String className = null;
 392         if (clazz != null) {
 393             className = clazz.getName();
 394             if (codebase == null)
 395                 codebase = Util.getCodebase(clazz);
 396         } else {
 397             if (repId != null)
 398                 className = RepositoryId.cache.getId(repId).getClassName();
 399             if (className == null) // no repId or unrecognized repId
 400                 throw wrapper.unableLocateValueHelper(
 401                     CompletionStatus.COMPLETED_MAYBE);
 402         }
 403 
 404         try {
 405             ClassLoader clazzLoader =
 406                 (clazz == null ? null : clazz.getClassLoader());
 407             Class helperClass =
 408                 loadClassForClass(className+"Helper", codebase, clazzLoader,
 409                 clazz, clazzLoader);
 410             return (BoxedValueHelper)helperClass.newInstance();
 411 
 412         } catch (ClassNotFoundException cnfe) {
 413             throw wrapper.unableLocateValueHelper( CompletionStatus.COMPLETED_MAYBE,
 414                 cnfe );
 415         } catch (IllegalAccessException iae) {
 416             throw wrapper.unableLocateValueHelper( CompletionStatus.COMPLETED_MAYBE,
 417                 iae );
 418         } catch (InstantiationException ie) {
 419             throw wrapper.unableLocateValueHelper( CompletionStatus.COMPLETED_MAYBE,
 420                 ie );
 421         } catch (ClassCastException cce) {
 422             throw wrapper.unableLocateValueHelper( CompletionStatus.COMPLETED_MAYBE,
 423                 cce );
 424         }
 425     }
 426 
 427     /**
 428      * Get the factory for an IDLValue
 429      *
 430      * Throws MARSHAL exception if no factory found.
 431      */
 432     public static ValueFactory getFactory(Class clazz, String codebase,
 433                                ORB orb, String repId)
 434     {
 435         ValueFactory factory = null;
 436         if ((orb != null) && (repId != null)) {
 437             try {
 438                 factory = ((org.omg.CORBA_2_3.ORB)orb).lookup_value_factory(
 439                     repId);
 440             } catch (org.omg.CORBA.BAD_PARAM ex) {
 441                 // Try other way
 442             }
 443         }
 444 
 445         String className = null;
 446         if (clazz != null) {
 447             className = clazz.getName();
 448             if (codebase == null)
 449                 codebase = Util.getCodebase(clazz);
 450         } else {
 451             if (repId != null)
 452                 className = RepositoryId.cache.getId(repId).getClassName();
 453             if (className == null) // no repId or unrecognized repId
 454                 throw omgWrapper.unableLocateValueFactory(
 455                     CompletionStatus.COMPLETED_MAYBE);
 456         }
 457 
 458         // if earlier search found a non-default factory, or the same default
 459         // factory that loadClassForClass would return, bale out now...
 460         if (factory != null &&
 461             (!factory.getClass().getName().equals(className+"DefaultFactory") ||
 462              (clazz == null && codebase == null)))
 463             return factory;
 464 
 465         try {
 466             ClassLoader clazzLoader =
 467                 (clazz == null ? null : clazz.getClassLoader());
 468             Class factoryClass =
 469                 loadClassForClass(className+"DefaultFactory", codebase,
 470                 clazzLoader, clazz, clazzLoader);
 471             return (ValueFactory)factoryClass.newInstance();
 472 
 473         } catch (ClassNotFoundException cnfe) {
 474             throw omgWrapper.unableLocateValueFactory(
 475                 CompletionStatus.COMPLETED_MAYBE, cnfe);
 476         } catch (IllegalAccessException iae) {
 477             throw omgWrapper.unableLocateValueFactory(
 478                 CompletionStatus.COMPLETED_MAYBE, iae);
 479         } catch (InstantiationException ie) {
 480             throw omgWrapper.unableLocateValueFactory(
 481                 CompletionStatus.COMPLETED_MAYBE, ie);
 482         } catch (ClassCastException cce) {
 483             throw omgWrapper.unableLocateValueFactory(
 484                 CompletionStatus.COMPLETED_MAYBE, cce);
 485         }
 486     }
 487 
 488     /*
 489      * Load an RMI-IIOP Stub given a Tie.
 490      * @param tie the tie.
 491      * @param stubClass the stub class. May be null.
 492      * @param remoteCodebase the codebase to use. May be null.
 493      * @param onlyMostDerived if true, will fail if cannot load a stub for the
 494      * first repID in the tie. If false, will walk all repIDs.
 495      * @return the stub or null if not found.
 496      */
 497 
 498     public static Remote loadStub(Tie tie,
 499                                   PresentationManager.StubFactory stubFactory,
 500                                   String remoteCodebase,
 501                                   boolean onlyMostDerived)
 502     {
 503         StubEntry entry = null;
 504 
 505         // Do we already have it cached?
 506         synchronized (tieToStubCache) {
 507             Object cached = tieToStubCache.get(tie);
 508             if (cached == null) {
 509                 // No, so go try to load it...
 510                 entry = loadStubAndUpdateCache(
 511                         tie, stubFactory, remoteCodebase, onlyMostDerived);
 512             } else {
 513                 // Yes, is it a stub?  If not, it was a miss last
 514                 // time, so return null again...
 515                 if (cached != CACHE_MISS) {
 516                     // It's a stub.
 517                     entry = (StubEntry) cached;
 518 
 519                     // Does the cached stub meet the requirements
 520                     // of the caller? If the caller does not require
 521                     // the most derived stub and does not require
 522                     // a specific stub type, we don't have to check
 523                     // any further because the cached type is good
 524                     // enough...
 525                     if (!entry.mostDerived && onlyMostDerived) {
 526                         // We must reload because we do not have
 527                         // the most derived cached already...
 528                         // The stubFactory arg must be null here
 529                         // to force onlyMostDerived=true to work
 530                         // correctly.
 531                         entry = loadStubAndUpdateCache(tie,null,
 532                             remoteCodebase,true);
 533                     } else if (stubFactory != null &&
 534                         !StubAdapter.getTypeIds(entry.stub)[0].equals(
 535                             stubFactory.getTypeIds()[0]) )
 536                     {
 537                         // We do not have exactly the right stub. First, try to
 538                         // upgrade the cached stub by forcing it to the most
 539                         // derived stub...
 540                         entry = loadStubAndUpdateCache(tie,null,
 541                             remoteCodebase,true);
 542 
 543                         // If that failed, try again with the exact type
 544                         // we need...
 545                         if (entry == null) {
 546                             entry = loadStubAndUpdateCache(tie,stubFactory,
 547                                     remoteCodebase,onlyMostDerived);
 548                         }
 549                     } else {
 550                         // Use the cached stub. Is the delegate set?
 551                         try {
 552                             Delegate stubDel = StubAdapter.getDelegate(
 553                                 entry.stub ) ;
 554                         } catch (Exception e2) {
 555                             // No, so set it if we can...
 556                             try {
 557                                 Delegate del = StubAdapter.getDelegate(
 558                                     tie ) ;
 559                                 StubAdapter.setDelegate( entry.stub,
 560                                     del ) ;
 561                             } catch (Exception e) {}
 562                         }
 563                     }
 564                 }
 565             }
 566         }
 567 
 568         if (entry != null) {
 569             return (Remote)entry.stub;
 570         } else {
 571             return null;
 572         }
 573     }
 574 
 575     /*
 576      * Load an RMI-IIOP Stub given a Tie, but do not look in the cache.
 577      * This method must be called with the lock held for tieToStubCache.
 578      * @param tie the tie.
 579      * @param stubFactory the stub factory. May be null.
 580      * @param remoteCodebase the codebase to use. May be null.
 581      * @param onlyMostDerived if true, will fail if cannot load a stub for the
 582      * first repID in the tie. If false, will walk all repIDs.
 583      * @return the StubEntry or null if not found.
 584      */
 585     private static StubEntry loadStubAndUpdateCache (
 586         Tie tie, PresentationManager.StubFactory  stubFactory,
 587         String remoteCodebase, boolean onlyMostDerived)
 588     {
 589         org.omg.CORBA.Object stub = null;
 590         StubEntry entry = null;
 591         boolean tieIsStub = StubAdapter.isStub( tie ) ;
 592 
 593         if (stubFactory != null) {
 594             try {
 595                 stub = stubFactory.makeStub();
 596             } catch (Throwable e) {
 597                 wrapper.stubFactoryCouldNotMakeStub( e ) ;
 598                 if (e instanceof ThreadDeath) {
 599                     throw (ThreadDeath) e;
 600                 }
 601             }
 602         } else {
 603             String[] ids = null;
 604             if (tieIsStub) {
 605                 ids = StubAdapter.getTypeIds( tie ) ;
 606             } else {
 607                 // This will throw an exception if the tie
 608                 // is not a Servant.  XXX Handle this better?
 609                 ids = ((org.omg.PortableServer.Servant)tie).
 610                       _all_interfaces( null, null );
 611             }
 612 
 613             if (remoteCodebase == null) {
 614                 remoteCodebase = Util.getCodebase(tie.getClass());
 615             }
 616 
 617             if (ids.length == 0) {
 618                 stub = new org.omg.stub.java.rmi._Remote_Stub();
 619             } else {
 620                 // Now walk all the RepIDs till we find a stub or fail...
 621                 for (int i = 0; i < ids.length; i++) {
 622                     if (ids[i].length() == 0) {
 623                         stub = new org.omg.stub.java.rmi._Remote_Stub();
 624                         break;
 625                     }
 626 
 627                     try {
 628                         PresentationManager.StubFactoryFactory stubFactoryFactory =
 629                             com.sun.corba.se.spi.orb.ORB.getStubFactoryFactory();
 630                         RepositoryId rid = RepositoryId.cache.getId( ids[i] ) ;
 631                         String className = rid.getClassName() ;
 632                         boolean isIDLInterface = rid.isIDLType() ;
 633                         stubFactory = stubFactoryFactory.createStubFactory(
 634                             className, isIDLInterface, remoteCodebase, null,
 635                             tie.getClass().getClassLoader() ) ;
 636                         stub = stubFactory.makeStub();
 637                         break;
 638                     } catch (Exception e) {
 639                         wrapper.errorInMakeStubFromRepositoryId( e ) ;
 640                     }
 641 
 642                     if (onlyMostDerived)
 643                         break;
 644                 }
 645             }
 646         }
 647 
 648         if (stub == null) {
 649             // Stub == null, so cache the miss...
 650             tieToStubCache.put(tie,CACHE_MISS);
 651         } else {
 652             if (tieIsStub) {
 653                 try {
 654                     Delegate del = StubAdapter.getDelegate( tie ) ;
 655                     StubAdapter.setDelegate( stub, del ) ;
 656                 } catch( Exception e1 ) {
 657                     // The tie does not have a delegate set, so stash
 658                     // this tie away using the stub as a key so that
 659                     // later, when the stub is connected, we can find
 660                     // and connect the tie as well...
 661 
 662                     synchronized (stubToTieCache) {
 663                         stubToTieCache.put(stub,tie);
 664                     }
 665                 }
 666             } else {
 667                 // Tie extends Servant
 668                 try {
 669                     Delegate delegate = StubAdapter.getDelegate( tie ) ;
 670                     StubAdapter.setDelegate( stub, delegate ) ;
 671                 } catch( org.omg.CORBA.BAD_INV_ORDER bad) {
 672                     synchronized (stubToTieCache) {
 673                         stubToTieCache.put(stub,tie);
 674                     }
 675                 } catch( Exception e ) {
 676                     // Exception is caught because of any of the
 677                     // following reasons
 678                     // 1) POA is not associated with the TIE
 679                     // 2) POA Policies for the tie-associated POA
 680                     //    does not support _this_object() call.
 681                     throw wrapper.noPoa( e ) ;
 682                 }
 683             }
 684             // Update the cache...
 685             entry = new StubEntry(stub,onlyMostDerived);
 686             tieToStubCache.put(tie,entry);
 687         }
 688 
 689         return entry;
 690     }
 691 
 692     /*
 693      * If we loadStub(Tie,...) stashed away a tie which was
 694      * not connected, remove it from the cache and return
 695      * it.
 696      */
 697     public static Tie getAndForgetTie (org.omg.CORBA.Object stub) {
 698         synchronized (stubToTieCache) {
 699             return (Tie) stubToTieCache.remove(stub);
 700         }
 701     }
 702 
 703     /*
 704      * Remove any cached Stub for the given tie.
 705      */
 706     public static void purgeStubForTie (Tie tie) {
 707         StubEntry entry;
 708         synchronized (tieToStubCache) {
 709             entry = (StubEntry)tieToStubCache.remove(tie);
 710         }
 711         if (entry != null) {
 712             synchronized (stubToTieCache) {
 713                 stubToTieCache.remove(entry.stub);
 714             }
 715         }
 716     }
 717 
 718     /*
 719      * Remove cached tie/servant pair.
 720      */
 721     public static void purgeTieAndServant (Tie tie) {
 722         synchronized (tieCache) {
 723             Object target = tie.getTarget();
 724             if (target != null)
 725                 tieCache.remove(target);
 726         }
 727     }
 728 
 729     /*
 730      * Convert a RepId to a stubName...
 731      */
 732     public static String stubNameFromRepID (String repID) {
 733 
 734         // Convert the typeid to a RepositoryId instance, get
 735         // the className and mangle it as needed...
 736 
 737         RepositoryId id = RepositoryId.cache.getId(repID);
 738         String className = id.getClassName();
 739 
 740         if (id.isIDLType()) {
 741             className = idlStubName(className);
 742         } else {
 743             className = stubName(className);
 744         }
 745         return className;
 746     }
 747 
 748 
 749     /*
 750      * Load an RMI-IIOP Stub.  This is used in PortableRemoteObject.narrow.
 751      */
 752     public static Remote loadStub (org.omg.CORBA.Object narrowFrom,
 753                                    Class narrowTo)
 754     {
 755         Remote result = null;
 756 
 757         try {
 758             // Get the codebase from the delegate to use when loading
 759             // the new stub, if possible...
 760             String codebase = null;
 761             try {
 762                 // We can't assume that narrowFrom is a CORBA_2_3 stub, yet
 763                 // it may have a 2_3 Delegate that provides a codebase.  Swallow
 764                 // the ClassCastException otherwise.
 765                 Delegate delegate = StubAdapter.getDelegate( narrowFrom ) ;
 766                 codebase = ((org.omg.CORBA_2_3.portable.Delegate)delegate).
 767                     get_codebase(narrowFrom);
 768 
 769             } catch (ClassCastException e) {
 770                 wrapper.classCastExceptionInLoadStub( e ) ;
 771             }
 772 
 773             PresentationManager.StubFactoryFactory sff =
 774                 com.sun.corba.se.spi.orb.ORB.getStubFactoryFactory() ;
 775             PresentationManager.StubFactory sf = sff.createStubFactory(
 776                 narrowTo.getName(), false, codebase, narrowTo,
 777                 narrowTo.getClassLoader() ) ;
 778             result = (Remote)sf.makeStub() ;
 779             StubAdapter.setDelegate( result,
 780                 StubAdapter.getDelegate( narrowFrom ) ) ;
 781         } catch (Exception err) {
 782             wrapper.exceptionInLoadStub( err ) ;
 783         }
 784 
 785         return result;
 786     }
 787 
 788     /*
 789      * Load an RMI-IIOP Stub class.  This is used in the
 790      * StaticStubFactoryFactory code.
 791      */
 792     public static Class loadStubClass(String repID,
 793                                       String remoteCodebase,
 794                                       Class expectedType)
 795         throws ClassNotFoundException
 796     {
 797         // Get the repID and check for "" special case.
 798         // We should never be called with it (See CDRInputStream
 799         // and the loadStub() method)...
 800 
 801         if (repID.length() == 0) {
 802             throw new ClassNotFoundException();
 803         }
 804 
 805         // Get the stubname from the repID and load
 806         // the class. If we have a valid 'sender', fall
 807         // back to using its codebase if we need to...
 808         String className = Utility.stubNameFromRepID(repID);
 809         ClassLoader expectedTypeClassLoader = (expectedType == null ? null :
 810             expectedType.getClassLoader());
 811 
 812         try {
 813               return loadClassOfType(className,
 814                                        remoteCodebase,
 815                                        expectedTypeClassLoader,
 816                                        expectedType,
 817                                        expectedTypeClassLoader);
 818         } catch (ClassNotFoundException e) {
 819             return loadClassOfType(PackagePrefixChecker.packagePrefix() + className,
 820                                    remoteCodebase,
 821                                    expectedTypeClassLoader,
 822                                    expectedType,
 823                                    expectedTypeClassLoader);
 824         }
 825     }
 826 
 827     /**
 828      * Create an RMI stub name.
 829      */
 830     public static String stubName (String className)
 831     {
 832         return stubName( className, false ) ;
 833     }
 834 
 835     public static String dynamicStubName( String className )
 836     {
 837         return stubName( className, true ) ;
 838     }
 839 
 840     private static String stubName( String className,
 841         boolean isDynamic )
 842     {
 843         String name = stubNameForCompiler( className, isDynamic ) ;
 844         if (PackagePrefixChecker.hasOffendingPrefix( name ))
 845             name = PackagePrefixChecker.packagePrefix() + name ;
 846         return name ;
 847     }
 848 
 849     public static String stubNameForCompiler (String className)
 850     {
 851         return stubNameForCompiler( className, false ) ;
 852     }
 853 
 854     private static String stubNameForCompiler( String className,
 855         boolean isDynamic )
 856     {
 857         int index = className.indexOf('$');
 858         if (index < 0) {
 859             index = className.lastIndexOf('.');
 860         }
 861 
 862         String suffix = isDynamic ? DYNAMIC_STUB_SUFFIX :
 863             RMI_STUB_SUFFIX ;
 864 
 865         if (index > 0) {
 866             return className.substring(0,index+1) + STUB_PREFIX +
 867                 className.substring(index+1) + suffix;
 868         } else {
 869             return STUB_PREFIX + className + suffix;
 870         }
 871     }
 872 
 873     /**
 874      * Create an RMI tie name.
 875      */
 876     public static String tieName (String className)
 877     {
 878         return
 879             PackagePrefixChecker.hasOffendingPrefix(tieNameForCompiler(className)) ?
 880             PackagePrefixChecker.packagePrefix() + tieNameForCompiler(className) :
 881             tieNameForCompiler(className);
 882     }
 883 
 884     public static String tieNameForCompiler (String className)
 885     {
 886         int index = className.indexOf('$');
 887         if (index < 0) {
 888             index = className.lastIndexOf('.');
 889         }
 890         if (index > 0) {
 891             return className.substring(0,index+1) +
 892                 STUB_PREFIX +
 893                 className.substring(index+1) +
 894                 TIE_SUFIX;
 895         } else {
 896             return STUB_PREFIX +
 897                 className +
 898                 TIE_SUFIX;
 899         }
 900     }
 901 
 902     /**
 903      * Throws the CORBA equivalent of a java.io.NotSerializableException
 904      */
 905     public static void throwNotSerializableForCorba(String className) {
 906         throw omgWrapper.notSerializable( CompletionStatus.COMPLETED_MAYBE,
 907             className ) ;
 908     }
 909 
 910     /**
 911      * Create an IDL stub name.
 912      */
 913     public static String idlStubName(String className)
 914     {
 915         String result = null;
 916         int index = className.lastIndexOf('.');
 917         if (index > 0) {
 918             result = className.substring(0,index+1) +
 919                 STUB_PREFIX +
 920                 className.substring(index+1) +
 921                 IDL_STUB_SUFFIX;
 922         } else {
 923             result = STUB_PREFIX +
 924                 className +
 925                 IDL_STUB_SUFFIX;
 926         }
 927         return result;
 928     }
 929 
 930     public static void printStackTrace()
 931     {
 932         Throwable thr = new Throwable( "Printing stack trace:" ) ;
 933         thr.fillInStackTrace() ;
 934         thr.printStackTrace() ;
 935     }
 936 
 937     /**
 938      * Read an object reference from the input stream and narrow
 939      * it to the desired type.
 940      * @param in the stream to read from.
 941      * @throws ClassCastException if narrowFrom cannot be cast to narrowTo.
 942      */
 943     public static Object readObjectAndNarrow(InputStream in,
 944                                              Class narrowTo)
 945         throws ClassCastException
 946     {
 947         Object result = in.read_Object();
 948         if (result != null)
 949             return PortableRemoteObject.narrow(result, narrowTo);
 950         else
 951             return null;
 952     }
 953 
 954     /**
 955      * Read an abstract interface type from the input stream and narrow
 956      * it to the desired type.
 957      * @param in the stream to read from.
 958      * @throws ClassCastException if narrowFrom cannot be cast to narrowTo.
 959      */
 960     public static Object readAbstractAndNarrow(
 961         org.omg.CORBA_2_3.portable.InputStream in, Class narrowTo)
 962         throws ClassCastException
 963     {
 964         Object result = in.read_abstract_interface();
 965         if (result != null)
 966             return PortableRemoteObject.narrow(result, narrowTo);
 967         else
 968             return null;
 969     }
 970 
 971 
 972     /** Converts an Ascii Character into Hexadecimal digit
 973      */
 974     static int hexOf( char x )
 975     {
 976         int val;
 977 
 978         val = x - '0';
 979         if (val >=0 && val <= 9)
 980             return val;
 981 
 982         val = (x - 'a') + 10;
 983         if (val >= 10 && val <= 15)
 984             return val;
 985 
 986         val = (x - 'A') + 10;
 987         if (val >= 10 && val <= 15)
 988             return val;
 989 
 990         throw wrapper.badHexDigit() ;
 991     }
 992 }
 993 
 994 class StubEntry {
 995     org.omg.CORBA.Object stub;
 996     boolean mostDerived;
 997 
 998     StubEntry(org.omg.CORBA.Object stub, boolean mostDerived) {
 999         this.stub = stub;
1000         this.mostDerived = mostDerived;
1001     }
1002 }