Utility.java revision 608:7e06bf1dcb09
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
33package com.sun.corba.se.impl.util;
34
35import org.omg.CORBA.SystemException;
36import org.omg.CORBA.CompletionStatus;
37import org.omg.CORBA.BAD_OPERATION;
38import org.omg.CORBA.BAD_INV_ORDER;
39import org.omg.CORBA.BAD_PARAM;
40import org.omg.CORBA.ORB;
41import org.omg.CORBA.Any;
42import org.omg.CORBA.TypeCode;
43import org.omg.CORBA.Principal;
44import org.omg.CORBA.portable.InputStream;
45import org.omg.CORBA.portable.OutputStream;
46import org.omg.CORBA.portable.BoxedValueHelper;
47import org.omg.CORBA.portable.ValueFactory;
48import org.omg.CORBA.portable.Streamable;
49import org.omg.CORBA.portable.Delegate;
50
51
52import java.util.Hashtable;
53import java.util.NoSuchElementException;
54
55import java.rmi.Remote;
56import java.rmi.NoSuchObjectException;
57import java.rmi.RemoteException;
58import java.rmi.server.RemoteStub;
59
60import javax.rmi.PortableRemoteObject;
61import javax.rmi.CORBA.Stub;
62import javax.rmi.CORBA.Tie;
63import javax.rmi.CORBA.Util;
64
65import java.io.Serializable;
66import java.io.File;
67import java.io.FileInputStream;
68
69import org.omg.PortableServer.POA;
70
71import com.sun.org.omg.SendingContext.CodeBase;
72
73import com.sun.corba.se.spi.logging.CORBALogDomains ;
74import com.sun.corba.se.spi.presentation.rmi.PresentationManager;
75import com.sun.corba.se.spi.presentation.rmi.StubAdapter ;
76
77import com.sun.corba.se.impl.logging.UtilSystemException ;
78import com.sun.corba.se.impl.logging.OMGSystemException ;
79
80/**
81 *  Handy class full of static functions.
82 */
83public 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
994class 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}
1003