StubGenerator.java revision 715:e2c563af9ef4
1/*
2 * Copyright (c) 1998, 2013, 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 sun.rmi.rmic.iiop;
34
35import java.io.File;
36import java.io.IOException;
37import java.io.SerializablePermission;
38import java.security.AccessController;
39import java.security.PrivilegedAction;
40import java.util.Vector;
41import java.util.Hashtable;
42import java.util.Enumeration;
43import sun.tools.java.Identifier;
44import sun.tools.java.ClassNotFound;
45import sun.tools.java.ClassDefinition;
46import sun.tools.java.ClassDeclaration;
47import sun.tools.java.CompilerError;
48import sun.rmi.rmic.IndentingWriter;
49import java.util.HashSet;
50import java.util.Arrays;
51import com.sun.corba.se.impl.util.Utility;
52import com.sun.corba.se.impl.util.PackagePrefixChecker;
53import sun.rmi.rmic.Main;
54
55
56/**
57 * An IIOP stub/tie generator for rmic.
58 *
59 * @author      Bryan Atsatt
60 * @author      Anil Vijendran
61 * @author      M. Mortazavi
62 */
63
64public class StubGenerator extends sun.rmi.rmic.iiop.Generator {
65
66    private static final String DEFAULT_STUB_CLASS = "javax.rmi.CORBA.Stub";
67    private static final String DEFAULT_TIE_CLASS = "org.omg.CORBA_2_3.portable.ObjectImpl";
68    private static final String DEFAULT_POA_TIE_CLASS = "org.omg.PortableServer.Servant";
69
70    protected boolean reverseIDs = false;
71    protected boolean localStubs = true;
72    protected boolean standardPackage = false;
73    protected boolean useHash = true;
74    protected String stubBaseClass = DEFAULT_STUB_CLASS;
75    protected String tieBaseClass = DEFAULT_TIE_CLASS;
76    protected HashSet namesInUse = new HashSet();
77    protected Hashtable classesInUse = new Hashtable();
78    protected Hashtable imports = new Hashtable();
79    protected int importCount = 0;
80    protected String currentPackage = null;
81    protected String currentClass = null;
82    protected boolean castArray = false;
83    protected Hashtable transactionalObjects = new Hashtable() ;
84    protected boolean POATie = false ;
85    protected boolean emitPermissionCheck = false;
86
87    /**
88     * Default constructor for Main to use.
89     */
90    public StubGenerator() {
91    }
92
93    /**
94     * Overridden in order to set the standardPackage flag.
95     */
96    public void generate(
97            sun.rmi.rmic.BatchEnvironment env,
98            ClassDefinition cdef, File destDir) {
99        ((sun.rmi.rmic.iiop.BatchEnvironment)env).
100                setStandardPackage(standardPackage);
101        super.generate(env, cdef, destDir);
102    }
103
104    /**
105     * Return true if a new instance should be created for each
106     * class on the command line. Subclasses which return true
107     * should override newInstance() to return an appropriately
108     * constructed instance.
109     */
110    protected boolean requireNewInstance() {
111        return false;
112    }
113
114    /**
115     * Return true if non-conforming types should be parsed.
116     * @param stack The context stack.
117     */
118    protected boolean parseNonConforming(ContextStack stack) {
119
120        // We let the environment setting decide so that
121        // another generator (e.g. IDLGenerator) can change
122        // it and we will just go with the flow...
123
124        return stack.getEnv().getParseNonConforming();
125    }
126
127    /**
128     * Create and return a top-level type.
129     * @param cdef The top-level class definition.
130     * @param stack The context stack.
131     * @return The compound type or null if is non-conforming.
132     */
133    protected CompoundType getTopType(ClassDefinition cdef, ContextStack stack) {
134
135        CompoundType result = null;
136
137        // Do we have an interface?
138
139        if (cdef.isInterface()) {
140
141            // Yes, so first try Abstract...
142
143            result = AbstractType.forAbstract(cdef,stack,true);
144
145            if (result == null) {
146
147                // Then try Remote...
148
149                result = RemoteType.forRemote(cdef,stack,false);
150            }
151        } else {
152
153            // Not an interface, so try Implementation...
154
155            result = ImplementationType.forImplementation(cdef,stack,false);
156        }
157
158        return result;
159    }
160
161    /**
162     * Examine and consume command line arguments.
163     * @param argv The command line arguments. Ignore null
164     * and unknown arguments. Set each consumed argument to null.
165     * @param error Report any errors using the main.error() methods.
166     * @return true if no errors, false otherwise.
167     */
168    public boolean parseArgs(String argv[], Main main) {
169        Object marker = new Object() ;
170
171        // Reset any cached options...
172
173        reverseIDs = false;
174        localStubs = true;
175        useHash = true;
176        stubBaseClass = DEFAULT_STUB_CLASS;
177        //       tieBaseClass = DEFAULT_TIE_CLASS;
178        transactionalObjects = new Hashtable() ;
179
180        // Parse options...
181
182        boolean result = super.parseArgs(argv,main);
183        if (result) {
184            for (int i = 0; i < argv.length; i++) {
185                if (argv[i] != null) {
186                    String arg = argv[i].toLowerCase();
187                    if (arg.equals("-iiop")) {
188                        argv[i] = null;
189                    } else if (arg.equals("-xreverseids")) {
190                        reverseIDs = true;
191                        argv[i] = null;
192                    } else if (arg.equals("-nolocalstubs")) {
193                        localStubs = false;
194                        argv[i] = null;
195                    } else if (arg.equals("-xnohash")) {
196                        useHash = false;
197                        argv[i] = null;
198                    } else if (argv[i].equals("-standardPackage")) {
199                        standardPackage = true;
200                        argv[i] = null;
201                    } else if (argv[i].equals("-emitPermissionCheck")) {
202                        emitPermissionCheck = true;
203                        argv[i] = null;
204                    } else if (arg.equals("-xstubbase")) {
205                        argv[i] = null;
206                        if (++i < argv.length && argv[i] != null && !argv[i].startsWith("-")) {
207                            stubBaseClass = argv[i];
208                            argv[i] = null;
209                        } else {
210                            main.error("rmic.option.requires.argument", "-Xstubbase");
211                            result = false;
212                        }
213                    } else if (arg.equals("-xtiebase")) {
214                        argv[i] = null;
215                        if (++i < argv.length && argv[i] != null && !argv[i].startsWith("-")) {
216                            tieBaseClass = argv[i];
217                            argv[i] = null;
218                        } else {
219                            main.error("rmic.option.requires.argument", "-Xtiebase");
220                            result = false;
221                        }
222                    } else if (arg.equals("-transactional" )) {
223                        // Scan for the next non-flag argument.
224                        // Assume that it is a class name and add it
225                        // to the list of transactional classes.
226                        for ( int ctr=i+1; ctr<argv.length; ctr++ ) {
227                            if (argv[ctr].charAt(1) != '-') {
228                                transactionalObjects.put( argv[ctr], marker ) ;
229                                break ;
230                            }
231                        }
232                        argv[i] = null;
233                    } else if (arg.equals( "-poa" )) {
234                        POATie = true ;
235                        argv[i] = null;
236                    }
237                }
238            }
239        }
240        if(POATie){
241            tieBaseClass = DEFAULT_POA_TIE_CLASS;
242        } else {
243            tieBaseClass = DEFAULT_TIE_CLASS;
244        }
245        return result;
246    }
247
248    /**
249     * Return an array containing all the file names and types that need to be
250     * generated for the given top-level type.  The file names must NOT have an
251     * extension (e.g. ".java").
252     * @param topType The type returned by getTopType().
253     * @param alreadyChecked A set of Types which have already been checked.
254     *  Intended to be passed to topType.collectMatching(filter,alreadyChecked).
255     */
256    protected OutputType[] getOutputTypesFor(CompoundType topType,
257                                             HashSet alreadyChecked) {
258
259        // We want to generate stubs for all remote and implementation types,
260        // so collect them up.
261        //
262        // We use the form of collectMatching which allows us to pass in a set of
263        // types which have previously been checked. By doing so, we ensure that if
264        // the command line contains Hello and HelloImpl, we will only generate
265        // output for Hello once...
266
267        int filter = TYPE_REMOTE | TYPE_IMPLEMENTATION;
268        Type[] genTypes = topType.collectMatching(filter,alreadyChecked);
269        int count = genTypes.length;
270        Vector list = new Vector(count+5);
271        BatchEnvironment theEnv = topType.getEnv();
272
273        // Now walk all types...
274
275        for (int i = 0; i < genTypes.length; i++) {
276
277            Type type = genTypes[i];
278            String typeName = type.getName();
279            boolean createStub = true;
280
281            // Is it an implementation type?
282
283            if (type instanceof ImplementationType) {
284
285                // Yes, so add a tie for it...
286
287                list.addElement(new OutputType(Utility.tieNameForCompiler(typeName), type));
288
289                // Does it have more than 1 remote interface?  If so, we
290                // want to create a stub for it...
291
292                int remoteInterfaceCount = 0;
293                InterfaceType[] interfaces = ((CompoundType)type).getInterfaces();
294                for (int j = 0; j < interfaces.length; j++) {
295                    if (interfaces[j].isType(TYPE_REMOTE) &&
296                        !interfaces[j].isType(TYPE_ABSTRACT)) {
297                        remoteInterfaceCount++;
298                    }
299                }
300
301                if (remoteInterfaceCount <= 1) {
302
303                    // No, so do not create a stub for this type...
304
305                    createStub = false;
306                }
307            }
308
309            // Is it an abstract interface type?
310
311            if (type instanceof AbstractType) {
312
313                // Do not create a stub for this type...
314
315                createStub = false;  // d11141
316            }
317
318            if (createStub) {
319
320                // Add a stub for the type...
321
322                list.addElement(new OutputType(Utility.stubNameForCompiler(typeName), type));
323            }
324        }
325
326        // Copy list into array..
327
328        OutputType[] outputTypes = new OutputType[list.size()];
329        list.copyInto(outputTypes);
330        return outputTypes;
331    }
332
333    /**
334     * Return the file name extension for the given file name (e.g. ".java").
335     * All files generated with the ".java" extension will be compiled. To
336     * change this behavior for ".java" files, override the compileJavaSourceFile
337     * method to return false.
338     * @param outputType One of the items returned by getOutputTypesFor(...)
339     */
340    protected String getFileNameExtensionFor(OutputType outputType) {
341        return SOURCE_FILE_EXTENSION;
342    }
343
344    /**
345     * Write the output for the given OutputFileName into the output stream.
346     * @param name One of the items returned by getOutputTypesFor(...)
347     * @param alreadyChecked A set of Types which have already been checked.
348     *  Intended to be passed to Type.collectMatching(filter,alreadyChecked).
349     * @param writer The output stream.
350     */
351    protected void writeOutputFor(      OutputType outputType,
352                                        HashSet alreadyChecked,
353                                        IndentingWriter writer) throws IOException {
354
355        String fileName = outputType.getName();
356        CompoundType theType = (CompoundType) outputType.getType();
357
358        // Are we doing a Stub or Tie?
359
360        if (fileName.endsWith(Utility.RMI_STUB_SUFFIX)) {
361
362            // Stub.
363
364            writeStub(outputType,writer);
365
366        } else {
367
368            // Tie
369
370            writeTie(outputType,writer);
371        }
372    }
373
374    /**
375     * Write a stub for the specified type.
376     */
377    protected void writeStub(OutputType outputType,
378                             IndentingWriter p) throws IOException {
379
380        CompoundType theType = (CompoundType) outputType.getType();
381        RemoteType[] remoteInterfaces = getDirectRemoteInterfaces(theType);
382
383        // Write comment.
384
385        p.pln("// Stub class generated by rmic, do not edit.");
386        p.pln("// Contents subject to change without notice.");
387        p.pln();
388
389        // Set our standard classes...
390
391        setStandardClassesInUse(theType,true);
392
393        // Add classes for this type...
394
395        addClassesInUse(theType,remoteInterfaces);
396
397        // Write package and import statements...
398
399        writePackageAndImports(p);
400
401//        generate
402//        import java.security.AccessController;
403//        import java.security.PrivilegedAction;
404//        import java.io.SerializablePermission;
405        if (emitPermissionCheck) {
406            p.pln("import java.security.AccessController;");
407            p.pln("import java.security.PrivilegedAction;");
408            p.pln("import java.io.SerializablePermission;");
409            p.pln();
410            p.pln();
411        }
412
413        // Declare the stub class; implement all remote interfaces.
414
415        p.p("public class " + currentClass);
416
417        p.p(" extends " + getName(stubBaseClass));
418        p.p(" implements ");
419        if (remoteInterfaces.length > 0) {
420            for(int i = 0; i < remoteInterfaces.length; i++) {
421                if (i > 0) {
422                    p.pln(",");
423                }
424                String objName = testUtil(getName(remoteInterfaces[i]), theType);
425                p.p(objName);
426            }
427        }
428
429        // Add java.rmi.Remote if this type does not implement it.
430        // This allows stubs for Abstract interfaces to be treated
431        // uniformly...
432
433        if (!implementsRemote(theType)) {
434            p.pln(",");
435            p.p(getName("java.rmi.Remote"));
436        }
437
438        p.plnI(" {");
439        p.pln();
440
441        // Write the ids...
442
443        writeIds( p, theType, false );
444        p.pln();
445
446        if (emitPermissionCheck) {
447
448            // produce the following generated code for example
449            //
450            // private transient boolean _instantiated = false;
451            //
452            // private static Void checkPermission() {
453            // SecurityManager sm = System.getSecurityManager();
454            // if (sm != null) {
455            //     sm.checkPermission(new SerializablePermission(
456            // "enableSubclassImplementation")); // testing
457            // }
458            // return null;
459            // }
460            //
461            // private _XXXXX_Stub(Void ignore) {
462            // }
463            //
464            // public _XXXXX_Stub() {
465            // this(checkPermission());
466            // _instantiated = true;
467            // }
468            //
469            // private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
470            //    checkPermission();
471            //    s.defaultReadObject();
472            //    _instantiated = true;
473            // }
474            //
475            // where XXXXX is the name of the remote interface
476
477                p.pln();
478                p.plnI("private transient boolean _instantiated = false;");
479                p.pln();
480                p.pO();
481                p.plnI("private static Void checkPermission() {");
482                p.plnI("SecurityManager sm = System.getSecurityManager();");
483                p.pln("if (sm != null) {");
484                p.pI();
485                p.plnI("sm.checkPermission(new SerializablePermission(");
486                p.plnI("\"enableSubclassImplementation\"));");
487                p.pO();
488                p.pO();
489                p.pOln("}");
490                p.pln("return null;");
491                p.pO();
492                p.pOln("}");
493                p.pln();
494                p.pO();
495
496                p.pI();
497                p.plnI("private " + currentClass + "(Void ignore) {  }");
498                p.pln();
499                p.pO();
500
501                p.plnI("public " + currentClass + "() { ");
502                p.pln("this(checkPermission());");
503                p.pln("_instantiated = true;");
504                p.pOln("}");
505                p.pln();
506                p.plnI("private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {");
507                p.plnI("checkPermission();");
508                p.pO();
509                p.pln("s.defaultReadObject();");
510                p.pln("_instantiated = true;");
511                p.pOln("}");
512                p.pln();
513                //p.pO();
514        }
515
516       if (!emitPermissionCheck) {
517            p.pI();
518       }
519
520        // Write the _ids() method...
521
522        p.plnI("public String[] _ids() { ");
523        p.pln("return (String[]) _type_ids.clone();");
524        p.pOln("}");
525
526        // Get all the methods and write each stub method...
527
528        CompoundType.Method[] remoteMethods = theType.getMethods();
529        int methodCount = remoteMethods.length;
530        if (methodCount > 0) {
531            boolean writeHeader = true;
532            for(int i = 0; i < methodCount; i++) {
533                if (!remoteMethods[i].isConstructor()) {
534                    if (writeHeader) {
535                        writeHeader = false;
536                    }
537                    p.pln();
538                    writeStubMethod(p, remoteMethods[i], theType);
539                }
540            }
541        }
542
543        // Write the cast array hack...
544
545        writeCastArray(p);
546
547        p.pOln("}");            // end stub class
548    }
549
550    void addClassInUse(String qualifiedName) {
551        String unqualifiedName = qualifiedName;
552        String packageName = null;
553        int index = qualifiedName.lastIndexOf('.');
554        if (index > 0) {
555            unqualifiedName = qualifiedName.substring(index+1);
556            packageName = qualifiedName.substring(0,index);
557        }
558        addClassInUse(unqualifiedName,qualifiedName,packageName);
559    }
560
561    void addClassInUse(Type type) {
562        if (!type.isPrimitive()) {
563            Identifier id = type.getIdentifier();
564            String name = IDLNames.replace(id.getName().toString(),". ",".");
565            String packageName = type.getPackageName();
566            String qualifiedName;
567            if (packageName != null) {
568                qualifiedName = packageName+"."+name;
569            } else {
570                qualifiedName = name;
571            }
572            addClassInUse(name,qualifiedName,packageName);
573        }
574    }
575
576    void addClassInUse(Type[] types) {
577        for (int i = 0; i < types.length; i++) {
578            addClassInUse(types[i]);
579        }
580    }
581
582    void addStubInUse(Type type) {
583        if (type.getIdentifier() != idCorbaObject &&
584            type.isType(TYPE_CORBA_OBJECT)) {
585            String stubName = getStubNameFor(type,false);
586            String packageName = type.getPackageName();
587            String fullName;
588            if (packageName == null) {
589                fullName = stubName;
590            } else {
591                fullName = packageName + "." + stubName;
592            }
593            addClassInUse(stubName,fullName,packageName);
594        }
595        if (type.isType(TYPE_REMOTE) ||
596            type.isType(TYPE_JAVA_RMI_REMOTE)) {
597            addClassInUse("javax.rmi.PortableRemoteObject");
598        }
599    }
600
601    String getStubNameFor(Type type, boolean qualified) {
602        String stubName;
603        String className;
604        if (qualified) {
605            className = type.getQualifiedName();
606        } else {
607            className = type.getName();
608        }
609        if (((CompoundType)type).isCORBAObject()) {
610            stubName = Utility.idlStubName(className);
611        } else {
612            stubName = Utility.stubNameForCompiler(className);
613        }
614        return stubName;
615    }
616
617    void addStubInUse(Type[] types) {
618        for (int i = 0; i < types.length; i++) {
619            addStubInUse(types[i]);
620        }
621    }
622
623    private static final String NO_IMPORT = new String();
624
625    void addClassInUse(String unqualifiedName, String qualifiedName, String packageName) {
626
627        // Have we already got an entry for this qualifiedName?
628
629        String currentName = (String)classesInUse.get(qualifiedName);
630
631        if (currentName == null) {
632
633            // No, never seen it before. Grab any existing import
634            // name and then decide what to do...
635
636            String importName = (String) imports.get(unqualifiedName);
637            String nameToUse = null;
638
639            if (packageName == null) {
640
641                // Default package, so doesn't matter which name to use...
642
643                nameToUse = unqualifiedName;
644
645            } else if (packageName.equals("java.lang")) {
646
647                // java.lang.*, so use unqualified name...
648
649                nameToUse = unqualifiedName;
650
651                // unless you want to be able to import things from the right place :--)
652
653                if(nameToUse.endsWith("_Stub")) nameToUse = Util.packagePrefix()+qualifiedName;
654
655            } else if (currentPackage != null && packageName.equals(currentPackage)) {
656
657                // Class in currentPackage, so use unqualified name...
658
659                nameToUse = unqualifiedName;
660
661                // Do we already have a previous import under this
662                // unqualified name?
663
664                if (importName != null) {
665
666                    // Yes, so we use qualifiedName...
667
668                    nameToUse = qualifiedName;
669
670                }
671
672            } else if (importName != null) {
673
674                // It is in some package for which we normally
675                // would import, but we have a previous import
676                // under this unqualified name. We must use
677                // the qualified name...
678
679                nameToUse = qualifiedName;
680
681                /*
682                  // Is the currentPackage the default package?
683
684                  if (currentPackage == null) {
685
686                  // Yes, so undo the import so that all
687                  // uses for this name will be qualified...
688
689                  String old = (String)imports.remove(unqualifiedName);
690                  classesInUse.put(old,old);
691                  importCount--;
692
693                  // Note that this name is in use but should
694                  // not be imported...
695
696                  imports.put(nameToUse,NO_IMPORT);
697                  }
698                */
699            } else if (qualifiedName.equals("org.omg.CORBA.Object")) {
700
701                // Always qualify this quy to avoid confusion...
702
703                nameToUse = qualifiedName;
704
705            } else {
706
707                // Default to using unqualified name, and add
708                // this guy to the imports...
709
710                // Check for nested class in which case we use
711                // the fully qualified name instead of imports
712                if (unqualifiedName.indexOf('.') != -1) {
713                    nameToUse = qualifiedName;
714                } else {
715                    nameToUse = unqualifiedName;
716                    imports.put(unqualifiedName,qualifiedName);
717                    importCount++;
718                }
719            }
720
721            // Now add the name...
722
723            classesInUse.put(qualifiedName,nameToUse);
724        }
725    }
726
727    String getName(Type type) {
728        if (type.isPrimitive()) {
729            return type.getName() + type.getArrayBrackets();
730        }
731        Identifier id = type.getIdentifier();
732        String name = IDLNames.replace(id.toString(),". ",".");
733        return getName(name) + type.getArrayBrackets();
734    }
735
736    // Added for Bug 4818753
737    String getExceptionName(Type type) {
738        Identifier id = type.getIdentifier();
739        return IDLNames.replace(id.toString(),". ",".");
740    }
741
742    String getName(String qualifiedName) {
743        return (String)classesInUse.get(qualifiedName);
744    }
745
746    String getName(Identifier id) {
747        return getName(id.toString());
748    }
749
750    String getStubName(Type type) {
751        String stubName = getStubNameFor(type,true);
752        return getName(stubName);
753    }
754
755    void setStandardClassesInUse(CompoundType type,
756                                 boolean stub) throws IOException {
757
758        // Reset our state...
759
760        currentPackage = type.getPackageName();
761        imports.clear();
762        classesInUse.clear();
763        namesInUse.clear();
764        importCount = 0;
765        castArray = false;
766
767        // Add the top-level type...
768
769        addClassInUse(type);
770
771        // Set current class name...
772
773        if (stub) {
774            currentClass = Utility.stubNameForCompiler(type.getName());
775        } else {
776            currentClass = Utility.tieNameForCompiler(type.getName());
777        }
778
779        // Add current class...
780
781        if (currentPackage == null) {
782            addClassInUse(currentClass,currentClass,currentPackage);
783        } else {
784            addClassInUse(currentClass,(currentPackage+"."+currentClass),currentPackage);
785        }
786
787        // Add standard classes...
788
789        addClassInUse("javax.rmi.CORBA.Util");
790        addClassInUse(idRemote.toString());
791        addClassInUse(idRemoteException.toString());
792        addClassInUse(idOutputStream.toString());
793        addClassInUse(idInputStream.toString());
794        addClassInUse(idSystemException.toString());
795        addClassInUse(idJavaIoSerializable.toString());
796        addClassInUse(idCorbaORB.toString());
797        addClassInUse(idReplyHandler.toString());
798
799        // Add stub/tie specific imports...
800
801        if (stub) {
802            addClassInUse(stubBaseClass);
803            addClassInUse("java.rmi.UnexpectedException");
804            addClassInUse(idRemarshalException.toString());
805            addClassInUse(idApplicationException.toString());
806            if (localStubs) {
807                addClassInUse("org.omg.CORBA.portable.ServantObject");
808            }
809        } else {
810            addClassInUse(type);
811            addClassInUse(tieBaseClass);
812            addClassInUse(idTieInterface.toString());
813            addClassInUse(idBadMethodException.toString());
814            addClassInUse(idPortableUnknownException.toString());
815            addClassInUse(idJavaLangThrowable.toString());
816        }
817    }
818
819    void addClassesInUse(CompoundType type, RemoteType[] interfaces) {
820
821        // Walk all methods and add types in use...
822
823        CompoundType.Method[] methods = type.getMethods();
824        for (int i = 0; i < methods.length; i++) {
825            addClassInUse(methods[i].getReturnType());
826            addStubInUse(methods[i].getReturnType());
827            addClassInUse(methods[i].getArguments());
828            addStubInUse(methods[i].getArguments());
829            addClassInUse(methods[i].getExceptions());
830            // bug 4473859: Also include narrower subtypes for use
831            addClassInUse(methods[i].getImplExceptions());
832        }
833
834        // If this is a stub, add all interfaces...
835
836        if (interfaces != null) {
837            addClassInUse(interfaces);
838        }
839    }
840
841    void writePackageAndImports(IndentingWriter p) throws IOException {
842
843        // Write package declaration...
844
845        if (currentPackage != null) {
846            p.pln("package " +
847                     Util.correctPackageName(
848                          currentPackage, false, standardPackage)
849                   + ";");
850            p.pln();
851        }
852
853        // Get imports into an array and sort them...
854
855        String[] names = new String[importCount];
856        int index = 0;
857        for (Enumeration e = imports.elements() ; e.hasMoreElements() ;) {
858            String it = (String) e.nextElement();
859            if (it != NO_IMPORT) {
860                names[index++] = it;
861            }
862        }
863
864        Arrays.sort(names,new StringComparator());
865
866        // Now dump them out...
867
868        for (int i = 0; i < importCount; i++) {
869            if(
870               Util.isOffendingPackage(names[i])
871               && names[i].endsWith("_Stub")
872               && String.valueOf(names[i].charAt(names[i].lastIndexOf(".")+1)).equals("_")
873               ){
874                p.pln("import " + PackagePrefixChecker.packagePrefix()+names[i]+";");
875            } else{
876                p.pln("import " + names[i] + ";");
877            }
878        }
879        p.pln();
880
881        // Include offending packages . . .
882        if ( currentPackage!=null && Util.isOffendingPackage(currentPackage) ){
883            p.pln("import " + currentPackage +".*  ;");
884        }
885        p.pln();
886
887    }
888
889    boolean implementsRemote(CompoundType theType) {
890        boolean result = theType.isType(TYPE_REMOTE) && !theType.isType(TYPE_ABSTRACT);
891
892        // If theType is not remote, look at all the interfaces
893        // until we find one that is...
894
895        if (!result) {
896            InterfaceType[] interfaces = theType.getInterfaces();
897            for (int i = 0; i < interfaces.length; i++) {
898                result = implementsRemote(interfaces[i]);
899                if (result) {
900                    break;
901                }
902            }
903        }
904
905        return result;
906    }
907
908    void writeStubMethod (  IndentingWriter p,
909                            CompoundType.Method method,
910                            CompoundType theType) throws IOException {
911
912        // Wtite the method declaration and opening brace...
913        String methodName = method.getName();
914        String methodIDLName = method.getIDLName();
915
916        Type paramTypes[] = method.getArguments();
917        String paramNames[] = method.getArgumentNames();
918        Type returnType = method.getReturnType();
919        ValueType[] exceptions = getStubExceptions(method,false);
920        boolean hasIOException = false;
921
922        addNamesInUse(method);
923        addNameInUse("_type_ids");
924
925        String objName = testUtil(getName(returnType), returnType);
926        p.p("public " + objName + " " + methodName + "(");
927        for(int i = 0; i < paramTypes.length; i++) {
928            if (i > 0)
929                p.p(", ");
930            p.p(getName(paramTypes[i]) + " " + paramNames[i]);
931        }
932
933        p.p(")");
934        if (exceptions.length > 0) {
935            p.p(" throws ");
936            for(int i = 0; i < exceptions.length; i++) {
937                if (i > 0) {
938                    p.p(", ");
939                }
940                // Added for Bug 4818753
941                p.p(getExceptionName(exceptions[i]));
942            }
943        }
944
945        p.plnI(" {");
946
947        // Now create the method body...
948        if (emitPermissionCheck) {
949            p.pln("if ((System.getSecurityManager() != null) && (!_instantiated)) {");
950            p.plnI("    throw new java.io.IOError(new java.io.IOException(\"InvalidObject \"));");
951            p.pOln("}");
952            p.pln();
953        }
954
955
956        if (localStubs) {
957            writeLocalStubMethodBody(p,method,theType);
958        } else {
959            writeNonLocalStubMethodBody(p,method,theType);
960        }
961
962        // Close out the method...
963
964        p.pOln("}");
965    }
966
967
968    void writeLocalStubMethodBody (IndentingWriter p,
969                                   CompoundType.Method method,
970                                   CompoundType theType) throws IOException {
971
972        String objName;
973        String paramNames[] = method.getArgumentNames();
974        Type returnType = method.getReturnType();
975        ValueType[] exceptions = getStubExceptions(method,false);
976        String methodName = method.getName();
977        String methodIDLName = method.getIDLName();
978
979        p.plnI("if (!Util.isLocal(this)) {");
980        writeNonLocalStubMethodBody(p,method,theType);
981        p.pOlnI("} else {");
982        String so = getVariableName("so");
983
984        p.pln("ServantObject "+so+" = _servant_preinvoke(\""+methodIDLName+"\","+getName(theType)+".class);");
985        p.plnI("if ("+so+" == null) {");
986        if (!returnType.isType(TYPE_VOID)) {
987            p.p("return ");
988        }
989        p.p(methodName+"(");
990        for (int i = 0; i < paramNames.length; i++) {
991            if (i > 0)
992                p.p(", ");
993            p.p(paramNames[i]);
994        }
995        p.pln(");");
996        if (returnType.isType(TYPE_VOID)) {
997            p.pln( "return ;" ) ;
998        }
999
1000        p.pOln("}");
1001        p.plnI("try {");
1002
1003        // Generate code to copy required arguments, and
1004        // get back the names by which all arguments are known...
1005
1006        String[] argNames = writeCopyArguments(method,p);
1007
1008        // Now write the method...
1009
1010        boolean copyReturn = mustCopy(returnType);
1011        String resultName = null;
1012        if (!returnType.isType(TYPE_VOID)) {
1013            if (copyReturn) {
1014                resultName = getVariableName("result");
1015                objName = testUtil(getName(returnType), returnType);
1016                p.p(objName+" "+resultName + " = ");
1017            } else {
1018                p.p("return ");
1019            }
1020        }
1021        objName = testUtil(getName(theType), theType);
1022        p.p("(("+objName+")"+so+".servant)."+methodName+"(");
1023
1024        for (int i = 0; i < argNames.length; i++) {
1025            if (i > 0)
1026                p.p(", ");
1027            p.p(argNames[i]);
1028        }
1029
1030        if (copyReturn) {
1031            p.pln(");");
1032            objName = testUtil(getName(returnType), returnType);
1033            p.pln("return ("+objName+")Util.copyObject("+resultName+",_orb());");
1034        } else {
1035            p.pln(");");
1036        }
1037
1038        String e1 = getVariableName("ex");
1039        String e2 = getVariableName("exCopy");
1040        p.pOlnI("} catch (Throwable "+e1+") {");
1041
1042        p.pln("Throwable "+e2+" = (Throwable)Util.copyObject("+e1+",_orb());");
1043        for(int i = 0; i < exceptions.length; i++) {
1044            if (exceptions[i].getIdentifier() != idRemoteException &&
1045                exceptions[i].isType(TYPE_VALUE)) {
1046                // Added for Bug 4818753
1047                p.plnI("if ("+e2+" instanceof "+getExceptionName(exceptions[i])+") {");
1048                p.pln("throw ("+getExceptionName(exceptions[i])+")"+e2+";");
1049                p.pOln("}");
1050            }
1051        }
1052
1053        p.pln("throw Util.wrapException("+e2+");");
1054        p.pOlnI("} finally {");
1055        p.pln("_servant_postinvoke("+so+");");
1056        p.pOln("}");
1057        p.pOln("}");
1058    }
1059
1060
1061    void writeNonLocalStubMethodBody (  IndentingWriter p,
1062                                        CompoundType.Method method,
1063                                        CompoundType theType) throws IOException {
1064
1065        String methodName = method.getName();
1066        String methodIDLName = method.getIDLName();
1067
1068        Type paramTypes[] = method.getArguments();
1069        String paramNames[] = method.getArgumentNames();
1070        Type returnType = method.getReturnType();
1071        ValueType[] exceptions = getStubExceptions(method,true);
1072
1073        String in = getVariableName("in");
1074        String out = getVariableName("out");
1075        String ex = getVariableName("ex");
1076
1077        // Decide if we need to use the new streams for
1078        // any of the read calls...
1079
1080        boolean needNewReadStreamClass = false;
1081        for (int i = 0; i < exceptions.length; i++) {
1082            if (exceptions[i].getIdentifier() != idRemoteException &&
1083                exceptions[i].isType(TYPE_VALUE) &&
1084                needNewReadStreamClass(exceptions[i])) {
1085                needNewReadStreamClass = true;
1086                break;
1087            }
1088        }
1089        if (!needNewReadStreamClass) {
1090            for (int i = 0; i < paramTypes.length; i++) {
1091                if (needNewReadStreamClass(paramTypes[i])) {
1092                    needNewReadStreamClass = true;
1093                    break;
1094                }
1095            }
1096        }
1097        if (!needNewReadStreamClass) {
1098            needNewReadStreamClass = needNewReadStreamClass(returnType);
1099        }
1100
1101        // Decide if we need to use the new streams for
1102        // any of the write calls...
1103
1104        boolean needNewWriteStreamClass = false;
1105        for (int i = 0; i < paramTypes.length; i++) {
1106            if (needNewWriteStreamClass(paramTypes[i])) {
1107                needNewWriteStreamClass = true;
1108                break;
1109            }
1110        }
1111
1112        // Now write the method, inserting casts where needed...
1113
1114        p.plnI("try {");
1115        if (needNewReadStreamClass) {
1116            p.pln(idExtInputStream + " "+in+" = null;");
1117        } else {
1118            p.pln(idInputStream + " "+in+" = null;");
1119        }
1120        p.plnI("try {");
1121
1122        String argStream = "null";
1123
1124        if (needNewWriteStreamClass) {
1125            p.plnI(idExtOutputStream + " "+out+" = ");
1126            p.pln("(" + idExtOutputStream + ")");
1127            p.pln("_request(\"" + methodIDLName + "\", true);");
1128            p.pO();
1129        } else {
1130            p.pln("OutputStream "+out+" = _request(\"" + methodIDLName + "\", true);");
1131        }
1132
1133        if (paramTypes.length > 0) {
1134            writeMarshalArguments(p, out, paramTypes, paramNames);
1135            p.pln();
1136        }
1137        argStream = out;
1138
1139        if (returnType.isType(TYPE_VOID)) {
1140            p.pln("_invoke(" + argStream + ");" );
1141        } else {
1142            if (needNewReadStreamClass) {
1143                p.plnI(in+" = (" + idExtInputStream + ")_invoke(" + argStream + ");");
1144                p.pO();
1145            } else {
1146                p.pln(in+" = _invoke(" + argStream + ");");
1147            }
1148            p.p("return ");
1149            writeUnmarshalArgument(p, in, returnType, null);
1150            p.pln();
1151        }
1152
1153        // Handle ApplicationException...
1154
1155        p.pOlnI("} catch ("+getName(idApplicationException)+" "+ex+") {");
1156        if (needNewReadStreamClass) {
1157            p.pln(in + " = (" + idExtInputStream + ") "+ex+".getInputStream();");
1158        } else {
1159            p.pln(in + " = "+ex+".getInputStream();");
1160        }
1161
1162        boolean idRead = false;
1163        boolean idAllocated = false;
1164        for(int i = 0; i < exceptions.length; i++) {
1165            if (exceptions[i].getIdentifier() != idRemoteException) {
1166
1167                // Is this our special-case IDLEntity exception?
1168
1169                if (exceptions[i].isIDLEntityException() && !exceptions[i].isCORBAUserException()) {
1170
1171                    // Yes.
1172
1173                    if (!idAllocated && !idRead) {
1174                        p.pln("String $_id = "+ex+".getId();");
1175                        idAllocated = true;
1176                    }
1177
1178                    String helperName = IDLNames.replace(exceptions[i].getQualifiedIDLName(false),"::",".");
1179                    helperName += "Helper";
1180                    p.plnI("if ($_id.equals("+helperName+".id())) {");
1181                    p.pln("throw "+helperName+".read("+in+");");
1182
1183                } else {
1184
1185                    // No.
1186
1187                    if (!idAllocated && !idRead) {
1188        p.pln("String $_id = "+in+".read_string();");
1189                        idAllocated = true;
1190                        idRead = true;
1191                    } else if (idAllocated && !idRead) {
1192                        p.pln("$_id = "+in+".read_string();");
1193                        idRead = true;
1194                    }
1195                    p.plnI("if ($_id.equals(\""+getExceptionRepositoryID(exceptions[i])+"\")) {");
1196                    // Added for Bug 4818753
1197                    p.pln("throw ("+getExceptionName(exceptions[i])+") "+in+".read_value(" + getExceptionName(exceptions[i]) + ".class);");
1198                }
1199                p.pOln("}");
1200            }
1201        }
1202        if (!idAllocated && !idRead) {
1203            p.pln("String $_id = "+in+".read_string();");
1204            idAllocated = true;
1205            idRead = true;
1206        } else if (idAllocated && !idRead) {
1207            p.pln("$_id = "+in+".read_string();");
1208            idRead = true;
1209        }
1210        p.pln("throw new UnexpectedException($_id);");
1211
1212        // Handle RemarshalException...
1213
1214        p.pOlnI("} catch ("+getName(idRemarshalException)+" "+ex+") {");
1215        if (!returnType.isType(TYPE_VOID)) {
1216            p.p("return ");
1217        }
1218        p.p(methodName + "(");
1219        for(int i = 0; i < paramTypes.length; i++) {
1220            if (i > 0) {
1221                p.p(",");
1222            }
1223            p.p(paramNames[i]);
1224        }
1225        p.pln(");");
1226
1227        // Ensure that we release the reply...
1228
1229        p.pOlnI("} finally {");
1230        p.pln("_releaseReply("+in+");");
1231
1232        p.pOln("}");
1233
1234        // Handle SystemException...
1235
1236        p.pOlnI("} catch (SystemException "+ex+") {");
1237        p.pln("throw Util.mapSystemException("+ex+");");
1238        p.pOln("}");
1239
1240        // returnResult(p,returnType);
1241    }
1242
1243    void allocateResult (IndentingWriter p,
1244                         Type returnType) throws IOException {
1245        if (!returnType.isType(TYPE_VOID)) {
1246            String objName = testUtil(getName(returnType), returnType);
1247            p.p(objName + " result = ");
1248        }
1249    }
1250
1251    int getTypeCode(Type type) {
1252
1253        int typeCode = type.getTypeCode();
1254
1255        // Handle late-breaking special case for
1256        // abstract IDL entities...
1257
1258        if ((type instanceof CompoundType) &&
1259            ((CompoundType)type).isAbstractBase()) {
1260            typeCode = TYPE_ABSTRACT;
1261        }
1262
1263        return typeCode;
1264    }
1265
1266
1267    /**
1268     * Write a snippet of Java code to marshal a value named "name" of
1269     * type "type" to the java.io.ObjectOutput stream named "stream".
1270     */
1271    void writeMarshalArgument(IndentingWriter p,
1272                              String streamName,
1273                              Type type, String name) throws IOException {
1274
1275        int typeCode = getTypeCode(type);
1276
1277        switch (typeCode) {
1278        case TYPE_BOOLEAN:
1279            p.p(streamName + ".write_boolean(" + name + ");");
1280            break;
1281        case TYPE_BYTE:
1282            p.p(streamName + ".write_octet(" + name + ");");
1283            break;
1284        case TYPE_CHAR:
1285            p.p(streamName + ".write_wchar(" + name + ");");
1286            break;
1287        case TYPE_SHORT:
1288            p.p(streamName + ".write_short(" + name + ");");
1289            break;
1290        case TYPE_INT:
1291            p.p(streamName + ".write_long(" + name + ");");
1292            break;
1293        case TYPE_LONG:
1294            p.p(streamName + ".write_longlong(" + name + ");");
1295            break;
1296        case TYPE_FLOAT:
1297            p.p(streamName + ".write_float(" + name + ");");
1298            break;
1299        case TYPE_DOUBLE:
1300            p.p(streamName + ".write_double(" + name + ");");
1301            break;
1302        case TYPE_STRING:
1303            p.p(streamName + ".write_value(" + name + "," + getName(type) + ".class);");
1304            break;
1305        case TYPE_ANY:
1306            p.p("Util.writeAny("+ streamName + "," + name + ");");
1307            break;
1308        case TYPE_CORBA_OBJECT:
1309            p.p(streamName + ".write_Object(" + name + ");");
1310            break;
1311        case TYPE_REMOTE:
1312            p.p("Util.writeRemoteObject("+ streamName + "," + name + ");");
1313            break;
1314        case TYPE_ABSTRACT:
1315            p.p("Util.writeAbstractObject("+ streamName + "," + name + ");");
1316            break;
1317        case TYPE_NC_INTERFACE:
1318            p.p(streamName + ".write_value((Serializable)" + name + "," + getName(type) + ".class);");
1319            break;
1320        case TYPE_VALUE:
1321            p.p(streamName + ".write_value(" + name + "," + getName(type) + ".class);");
1322            break;
1323        case TYPE_IMPLEMENTATION:
1324            p.p(streamName + ".write_value((Serializable)" + name + "," + getName(type) + ".class);");
1325            break;
1326        case TYPE_NC_CLASS:
1327            p.p(streamName + ".write_value((Serializable)" + name + "," + getName(type) + ".class);");
1328            break;
1329        case TYPE_ARRAY:
1330            castArray = true;
1331            p.p(streamName + ".write_value(cast_array(" + name + ")," + getName(type) + ".class);");
1332            break;
1333        case TYPE_JAVA_RMI_REMOTE:
1334            p.p("Util.writeRemoteObject("+ streamName + "," + name + ");");
1335            break;
1336        default:
1337            throw new Error("unexpected type code: " + typeCode);
1338        }
1339    }
1340
1341    /**
1342     * Write a snippet of Java code to unmarshal a value of type "type"
1343     * from the java.io.ObjectInput stream named "stream" into a variable
1344     * named "name" (if "name" is null, the value in unmarshalled and
1345     * discarded).
1346     */
1347    void writeUnmarshalArgument(IndentingWriter p,
1348                                String streamName,
1349                                Type type,
1350                                String name) throws IOException {
1351
1352        int typeCode = getTypeCode(type);
1353
1354        if (name != null) {
1355            p.p(name + " = ");
1356        }
1357
1358        switch (typeCode) {
1359        case TYPE_BOOLEAN:
1360            p.p(streamName + ".read_boolean();");
1361            break;
1362        case TYPE_BYTE:
1363            p.p(streamName + ".read_octet();");
1364            break;
1365        case TYPE_CHAR:
1366            p.p(streamName + ".read_wchar();");
1367            break;
1368        case TYPE_SHORT:
1369            p.p(streamName + ".read_short();");
1370            break;
1371        case TYPE_INT:
1372            p.p(streamName + ".read_long();");
1373            break;
1374        case TYPE_LONG:
1375            p.p(streamName + ".read_longlong();");
1376            break;
1377        case TYPE_FLOAT:
1378            p.p(streamName + ".read_float();");
1379            break;
1380        case TYPE_DOUBLE:
1381            p.p(streamName + ".read_double();");
1382            break;
1383        case TYPE_STRING:
1384            p.p("(String) " + streamName + ".read_value(" + getName(type) + ".class);");
1385            break;
1386        case TYPE_ANY:
1387            if (type.getIdentifier() != idJavaLangObject) {
1388                p.p("(" + getName(type) + ") ");
1389            }
1390            p.p("Util.readAny(" + streamName + ");");
1391            break;
1392        case TYPE_CORBA_OBJECT:
1393            if (type.getIdentifier() == idCorbaObject) {
1394                p.p("(" + getName(type) + ") " + streamName + ".read_Object();");
1395            } else {
1396                p.p("(" + getName(type) + ") " + streamName + ".read_Object(" + getStubName(type) + ".class);");
1397            }
1398            break;
1399        case TYPE_REMOTE:
1400            String objName = testUtil(getName(type), type);
1401            p.p("(" + objName + ") " +
1402                "PortableRemoteObject.narrow(" + streamName + ".read_Object(), " + objName + ".class);");
1403            break;
1404        case TYPE_ABSTRACT:
1405            p.p("(" + getName(type) + ") " + streamName + ".read_abstract_interface();");
1406            break;
1407        case TYPE_NC_INTERFACE:
1408            p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);");
1409            break;
1410        case TYPE_VALUE:
1411            p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);");
1412            break;
1413        case TYPE_IMPLEMENTATION:
1414            p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);");
1415            break;
1416        case TYPE_NC_CLASS:
1417            p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);");
1418            break;
1419        case TYPE_ARRAY:
1420            p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);");
1421            break;
1422        case TYPE_JAVA_RMI_REMOTE:
1423            p.p("(" + getName(type) + ") " +
1424                "PortableRemoteObject.narrow(" + streamName + ".read_Object(), " + getName(type) + ".class);");
1425            //      p.p("(" + getName(type) + ") " + streamName + ".read_Object(" + getStubName(type) + ".class);");
1426            break;
1427        default:
1428            throw new Error("unexpected type code: " + typeCode);
1429        }
1430    }
1431
1432    /**
1433     * Get a list of all the RepositoryIDs for interfaces
1434     * implemented directly or indirectly by theType. In the
1435     * case of an  ImplementationType which implements 2 or
1436     * more remote interfaces, this list will begin with the
1437     * Identifier for the implementation (see section 5.9 in
1438     * the Java -> IDL mapping). Ensures that the most derived
1439     * type is first in the list because the IOR is generated
1440     * using that entry in the _ids array.
1441     */
1442    String[] getAllRemoteRepIDs (CompoundType theType) {
1443
1444        String[] result;
1445
1446        // Collect up all the (inherited) remote interfaces
1447        // (ignores all the 'special' interfaces: Remote,
1448        // Serializable, Externalizable)...
1449
1450        Type[] types = collectAllRemoteInterfaces(theType);
1451
1452        int length = types.length;
1453        boolean haveImpl = theType instanceof ImplementationType;
1454        InterfaceType[] interfaces = theType.getInterfaces();
1455        int remoteCount = countRemote(interfaces,false);
1456        int offset = 0;
1457
1458        // Do we have an implementation type that implements
1459        // more than one remote interface?
1460
1461        if (haveImpl && remoteCount > 1) {
1462
1463            // Yes, so we need to insert it at the beginning...
1464
1465            result = new String[length + 1];
1466            result[0] = getRepositoryID(theType);
1467            offset = 1;
1468
1469        } else {
1470
1471            // No.
1472
1473            result = new String[length];
1474
1475            // Here we need to ensure that the most derived
1476            // interface ends up being first in the list. If
1477            // there is only one, we're done.
1478
1479            if (length > 1) {
1480
1481                // First, decide what the most derived type is...
1482
1483                String mostDerived = null;
1484
1485                if (haveImpl) {
1486
1487                    // If we get here, we know that there is only one
1488                    // direct remote interface, so just find it...
1489
1490                    for (int i = 0; i < interfaces.length; i++) {
1491                        if (interfaces[i].isType(TYPE_REMOTE)) {
1492                            mostDerived = interfaces[i].getRepositoryID();
1493                            break;
1494                        }
1495                    }
1496                } else {
1497
1498                    // If we get here we know that theType is a RemoteType
1499                    // so just use its id...
1500
1501                    mostDerived = theType.getRepositoryID();
1502                }
1503
1504                // Now search types list and make sure mostDerived is
1505                // at index zero...
1506
1507                for (int i = 0; i < length; i++) {
1508                    if (types[i].getRepositoryID() == mostDerived) {
1509
1510                        // Found it. Swap it if we need to...
1511
1512                        if (i > 0) {
1513                            Type temp = types[0];
1514                            types[0] = types[i];
1515                            types[i] = temp;
1516                        }
1517
1518                        break;
1519                    }
1520                }
1521            }
1522        }
1523
1524        // Now copy contents of the types array...
1525
1526        for (int i = 0; i < types.length; i++) {
1527            result[offset++] = getRepositoryID(types[i]);
1528        }
1529
1530        // If we're supposed to, reverse the array. This
1531        // is only done when the -testReverseIDs flag is
1532        // passed, and that should ONLY be done for test
1533        // cases. This is an undocumented feature.
1534
1535        if (reverseIDs) {
1536            int start = 0;
1537            int end = result.length -1;
1538            while (start < end) {
1539                String temp = result[start];
1540                result[start++] = result[end];
1541                result[end--] = temp;
1542            }
1543        }
1544
1545        return result;
1546    }
1547
1548    /**
1549     * Collect all the inherited remote interfaces.
1550     */
1551    Type[] collectAllRemoteInterfaces (CompoundType theType) {
1552        Vector list = new Vector();
1553
1554        // Collect up all the Remote interfaces, and get an instance
1555        // for java.rmi.Remote...
1556
1557        addRemoteInterfaces(list,theType);
1558
1559        // Create and return our results...
1560
1561        Type[] result = new Type[list.size()];
1562        list.copyInto(result);
1563
1564        return result;
1565    }
1566
1567    /**
1568     * Add all the inherited remote interfaces to list.
1569     */
1570    void addRemoteInterfaces(Vector list, CompoundType theType) {
1571
1572        if (theType != null) {
1573            if (theType.isInterface() && !list.contains(theType)) {
1574                list.addElement(theType);
1575            }
1576
1577            InterfaceType[] interfaces = theType.getInterfaces();
1578            for (int i = 0; i < interfaces.length; i++) {
1579
1580                if (interfaces[i].isType(TYPE_REMOTE)) {
1581                    addRemoteInterfaces(list,interfaces[i]);
1582                }
1583            }
1584
1585            addRemoteInterfaces(list,theType.getSuperclass());
1586        }
1587    }
1588
1589    /**
1590     * Get a list of all the remote interfaces which this stub
1591     * should declare.
1592     */
1593    RemoteType[] getDirectRemoteInterfaces (CompoundType theType) {
1594
1595        RemoteType[] result;
1596        InterfaceType[] interfaces = theType.getInterfaces();
1597
1598        // First, get a list of all the interfaces...
1599
1600        InterfaceType[] list;
1601
1602        // Because we can be passed either an ImplementationType
1603        // (which has interfaces) or a RemoteType (which is an
1604        // interface and may have interfaces) we must handle each
1605        // separately...
1606
1607        // Do we have an implementation type?
1608
1609        if (theType instanceof ImplementationType) {
1610
1611            // Yes, so list is exactly what this type
1612            // implements and is correct already.
1613
1614            list = interfaces;
1615
1616        } else {
1617
1618            // No, so list is just theType...
1619
1620            list = new InterfaceType[1];
1621            list[0] = (InterfaceType) theType;
1622        }
1623
1624        // Ok, now count up the remote interfaces, allocate
1625        // our result and fill it in...
1626
1627        int remoteCount = countRemote(list,false);
1628
1629        if (remoteCount == 0) {
1630            throw new CompilerError("iiop.StubGenerator: No remote interfaces!");
1631        }
1632
1633        result = new RemoteType[remoteCount];
1634        int offset = 0;
1635        for (int i = 0; i < list.length; i++) {
1636            if (list[i].isType(TYPE_REMOTE)) {
1637                result[offset++] = (RemoteType)list[i];
1638            }
1639        }
1640
1641        return result;
1642    }
1643
1644    int countRemote (Type[] list, boolean includeAbstract) {
1645        int remoteCount = 0;
1646        for (int i = 0; i < list.length; i++) {
1647            if (list[i].isType(TYPE_REMOTE) &&
1648                (includeAbstract || !list[i].isType(TYPE_ABSTRACT))) {
1649                remoteCount++;
1650            }
1651        }
1652
1653        return remoteCount;
1654    }
1655
1656    void writeCastArray(IndentingWriter p) throws IOException {
1657        if (castArray) {
1658            p.pln();
1659            p.pln("// This method is required as a work-around for");
1660            p.pln("// a bug in the JDK 1.1.6 verifier.");
1661            p.pln();
1662            p.plnI("private "+getName(idJavaIoSerializable)+" cast_array(Object obj) {");
1663            p.pln("return ("+getName(idJavaIoSerializable)+")obj;");
1664            p.pOln("}");
1665        }
1666    }
1667    void writeIds(IndentingWriter p, CompoundType theType, boolean isTie
1668                  ) throws IOException {
1669        p.plnI("private static final String[] _type_ids = {");
1670
1671        String[] ids = getAllRemoteRepIDs(theType);
1672
1673        if (ids.length >0 ) {
1674            for(int i = 0; i < ids.length; i++) {
1675                if (i > 0)
1676                    p.pln(", ");
1677                p.p("\"" + ids[i] + "\"");
1678            }
1679        } else {
1680           // Must be an implementation which only implements Remote...
1681           p.pln("\"\"");
1682        }
1683        String qname = theType.getQualifiedName() ;
1684        boolean isTransactional = isTie && transactionalObjects.containsKey( qname ) ;
1685        // Add TransactionalObject if needed.
1686        if (isTransactional) {
1687            // Have already written an id.
1688            p.pln( ", " ) ;
1689            p.pln( "\"IDL:omg.org/CosTransactions/TransactionalObject:1.0\"" ) ;
1690        } else if (ids.length > 0) {
1691            p.pln();
1692        }
1693        p.pOln("};");
1694    }
1695
1696
1697    /**
1698     * Write the Tie for the remote class to a stream.
1699     */
1700    protected void writeTie(OutputType outputType,
1701                            IndentingWriter p) throws IOException
1702    {
1703        CompoundType theType = (CompoundType) outputType.getType();
1704        RemoteType[] remoteInterfaces = null;
1705
1706        // Write comment...
1707        p.pln("// Tie class generated by rmic, do not edit.");
1708        p.pln("// Contents subject to change without notice.");
1709        p.pln();
1710
1711        // Set our standard classes...
1712        setStandardClassesInUse(theType,false);
1713
1714        // Add classes for this type...
1715        addClassesInUse(theType,remoteInterfaces);
1716
1717        // Write package and import statements...
1718        writePackageAndImports(p);
1719
1720        // Declare the tie class.
1721        p.p("public class " + currentClass + " extends " +
1722            getName(tieBaseClass) + " implements Tie");
1723
1724        // Add java.rmi.Remote if this type does not implement it.
1725        // This allows stubs for Abstract interfaces to be treated
1726        // uniformly...
1727        if (!implementsRemote(theType)) {
1728            p.pln(",");
1729            p.p(getName("java.rmi.Remote"));
1730        }
1731
1732        p.plnI(" {");
1733
1734        // Write data members...
1735        p.pln();
1736        p.pln("volatile private " + getName(theType) + " target = null;");
1737        p.pln();
1738
1739        // Write the ids...
1740        writeIds( p, theType, true ) ;
1741
1742        // Write setTarget method...
1743        p.pln();
1744        p.plnI("public void setTarget(Remote target) {");
1745        p.pln("this.target = (" + getName(theType) + ") target;");
1746        p.pOln("}");
1747
1748        // Write getTarget method...
1749        p.pln();
1750        p.plnI("public Remote getTarget() {");
1751        p.pln("return target;");
1752        p.pOln("}");
1753
1754        // Write thisObject method...
1755        p.pln();
1756        write_tie_thisObject_method(p,idCorbaObject);
1757
1758        // Write deactivate method...
1759        p.pln();
1760        write_tie_deactivate_method(p);
1761
1762        // Write get orb method...
1763        p.pln();
1764        p.plnI("public ORB orb() {");
1765        p.pln("return _orb();");
1766        p.pOln("}");
1767
1768        // Write set orb method...
1769        p.pln();
1770        write_tie_orb_method(p);
1771
1772        // Write the _ids() method...
1773        p.pln();
1774        write_tie__ids_method(p);
1775
1776        // Get all the methods...
1777        CompoundType.Method[] remoteMethods = theType.getMethods();
1778
1779        // Register all the argument names used, plus our
1780        // data member names...
1781
1782        addNamesInUse(remoteMethods);
1783        addNameInUse("target");
1784        addNameInUse("_type_ids");
1785
1786        // Write the _invoke method...
1787        p.pln();
1788
1789        String in = getVariableName("in");
1790        String _in = getVariableName("_in");
1791        String ex = getVariableName("ex");
1792        String method = getVariableName("method");
1793        String reply = getVariableName("reply");
1794
1795        p.plnI("public OutputStream  _invoke(String "+method+", InputStream "+_in+", " +
1796               "ResponseHandler "+reply+") throws SystemException {");
1797
1798        if (remoteMethods.length > 0) {
1799            p.plnI("try {");
1800            p.pln(getName(theType) + " target = this.target;");
1801            p.plnI("if (target == null) {");
1802            p.pln("throw new java.io.IOException();");
1803            p.pOln("}");
1804            p.plnI(idExtInputStream + " "+in+" = ");
1805            p.pln("(" + idExtInputStream + ") "+_in+";");
1806            p.pO();
1807
1808            // See if we should use a hash table style
1809            // comparison...
1810
1811            StaticStringsHash hash = getStringsHash(remoteMethods);
1812
1813            if (hash != null) {
1814                p.plnI("switch ("+method+"."+hash.method+") {");
1815                for (int i = 0; i < hash.buckets.length; i++) {
1816                    p.plnI("case "+hash.keys[i]+": ");
1817                    for (int j = 0; j < hash.buckets[i].length; j++) {
1818                        CompoundType.Method current = remoteMethods[hash.buckets[i][j]];
1819                        if (j > 0) {
1820                            p.pO("} else ");
1821                        }
1822                        p.plnI("if ("+method+".equals(\""+ current.getIDLName() +"\")) {");
1823                        writeTieMethod(p, theType,current);
1824                    }
1825                    p.pOln("}");
1826                    p.pO();
1827                }
1828            } else {
1829                for(int i = 0; i < remoteMethods.length; i++) {
1830                CompoundType.Method current = remoteMethods[i];
1831                if (i > 0) {
1832                    p.pO("} else ");
1833                }
1834
1835                p.plnI("if ("+method+".equals(\""+ current.getIDLName() +"\")) {");
1836                writeTieMethod(p, theType, current);
1837            }
1838            }
1839
1840            if (hash != null) {
1841                p.pI();
1842                //        p.plnI("default:");
1843            } else {
1844                //   p.pOlnI("} else {");
1845            }
1846            //              p.pln("throw new "+getName(idBadMethodException)+"();");
1847
1848            if (hash != null) {
1849                p.pO();
1850            }
1851            p.pOln("}");
1852            p.pln("throw new "+getName(idBadMethodException)+"();");
1853
1854            p.pOlnI("} catch ("+getName(idSystemException)+" "+ex+") {");
1855            p.pln("throw "+ex+";");
1856
1857            p.pOlnI("} catch ("+getName(idJavaLangThrowable)+" "+ex+") {");
1858            p.pln("throw new " + getName(idPortableUnknownException) + "("+ex+");");
1859            p.pOln("}");
1860        } else {
1861            // No methods...
1862
1863            p.pln("throw new " + getName(idBadMethodException) + "();");
1864        }
1865
1866        p.pOln("}");            // end invoke
1867
1868        // Write the cast array hack...
1869
1870        writeCastArray(p);
1871
1872        // End tie class...
1873        p.pOln("}");
1874    }
1875    public void catchWrongPolicy(IndentingWriter p) throws IOException {
1876        p.pln("");
1877    }
1878    public void catchServantNotActive(IndentingWriter p) throws IOException {
1879        p.pln("");
1880    }
1881    public void catchObjectNotActive(IndentingWriter p) throws IOException {
1882        p.pln("");
1883    }
1884
1885    public void write_tie_thisObject_method(IndentingWriter p,
1886                                            Identifier idCorbaObject)
1887        throws IOException
1888    {
1889        if(POATie){
1890            p.plnI("public " + idCorbaObject + " thisObject() {");
1891            /*
1892            p.pln("org.omg.CORBA.Object objref = null;");
1893            p.pln("try{");
1894            p.pln("objref = _poa().servant_to_reference(this);");
1895            p.pln("}catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){");
1896            catchWrongPolicy(p);
1897            p.pln("}catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){");
1898            catchServantNotActive(p);
1899            p.pln("}");
1900            p.pln("return objref;");
1901            */
1902            p.pln("return _this_object();");
1903            p.pOln("}");
1904        } else {
1905            p.plnI("public " + idCorbaObject + " thisObject() {");
1906            p.pln("return this;");
1907            p.pOln("}");
1908        }
1909    }
1910
1911    public void write_tie_deactivate_method(IndentingWriter p)
1912        throws IOException
1913    {
1914        if(POATie){
1915            p.plnI("public void deactivate() {");
1916            p.pln("try{");
1917            p.pln("_poa().deactivate_object(_poa().servant_to_id(this));");
1918            p.pln("}catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){");
1919            catchWrongPolicy(p);
1920            p.pln("}catch (org.omg.PortableServer.POAPackage.ObjectNotActive exception){");
1921            catchObjectNotActive(p);
1922            p.pln("}catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){");
1923            catchServantNotActive(p);
1924            p.pln("}");
1925            p.pOln("}");
1926        } else {
1927            p.plnI("public void deactivate() {");
1928            p.pln("_orb().disconnect(this);");
1929            p.pln("_set_delegate(null);");
1930            p.pln("target = null;");
1931            p.pOln("}");
1932        }
1933    }
1934
1935    public void write_tie_orb_method(IndentingWriter p)
1936        throws IOException
1937    {
1938        if(POATie){
1939        p.plnI("public void orb(ORB orb) {");
1940        /*
1941        p.pln("try{");
1942        p.pln("orb.connect(_poa().servant_to_reference(this));");
1943        p.pln("}catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){");
1944        catchWrongPolicy(p);
1945        p.pln("}catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){");
1946        catchServantNotActive(p);
1947        p.pln("}");
1948        */
1949        p.pln("try {");
1950        p.pln("    ((org.omg.CORBA_2_3.ORB)orb).set_delegate(this);");
1951        p.pln("}");
1952        p.pln("catch(ClassCastException e) {");
1953        p.pln("    throw new org.omg.CORBA.BAD_PARAM");
1954        p.pln("        (\"POA Servant requires an instance of org.omg.CORBA_2_3.ORB\");");
1955        p.pln("}");
1956        p.pOln("}");
1957        } else {
1958        p.plnI("public void orb(ORB orb) {");
1959        p.pln("orb.connect(this);");
1960        p.pOln("}");
1961        }
1962    }
1963
1964    public void write_tie__ids_method(IndentingWriter p)
1965        throws IOException
1966    {
1967        if(POATie){
1968        p.plnI("public String[] _all_interfaces(org.omg.PortableServer.POA poa, byte[] objectId){");
1969        p.pln("return (String[]) _type_ids.clone();");
1970        p.pOln("}");
1971        } else {
1972        p.plnI("public String[] _ids() { ");
1973        p.pln("return (String[]) _type_ids.clone();");
1974        p.pOln("}");
1975        }
1976    }
1977
1978
1979    StaticStringsHash getStringsHash (CompoundType.Method[] methods) {
1980        if (useHash && methods.length > 1) {
1981            String[] methodNames = new String[methods.length];
1982            for (int i = 0; i < methodNames.length; i++) {
1983                methodNames[i] = methods[i].getIDLName();
1984            }
1985            return new StaticStringsHash(methodNames);
1986        }
1987        return null;
1988    }
1989
1990    static boolean needNewReadStreamClass(Type type) {
1991        if (type.isType(TYPE_ABSTRACT)) {
1992            return true;
1993        }
1994        // Handle late-breaking special case for
1995        // abstract IDL entities...
1996        if ((type instanceof CompoundType) &&
1997            ((CompoundType)type).isAbstractBase()) {
1998            return true;
1999        }
2000        return needNewWriteStreamClass(type);
2001    }
2002
2003    static boolean needNewWriteStreamClass(Type type) {
2004        switch (type.getTypeCode()) {
2005        case TYPE_VOID:
2006        case TYPE_BOOLEAN:
2007        case TYPE_BYTE:
2008        case TYPE_CHAR:
2009        case TYPE_SHORT:
2010        case TYPE_INT:
2011        case TYPE_LONG:
2012        case TYPE_FLOAT:
2013        case TYPE_DOUBLE:           return false;
2014
2015        case TYPE_STRING:           return true;
2016        case TYPE_ANY:              return false;
2017        case TYPE_CORBA_OBJECT:     return false;
2018        case TYPE_REMOTE:           return false;
2019        case TYPE_ABSTRACT:         return false;
2020        case TYPE_NC_INTERFACE:     return true;
2021        case TYPE_VALUE:            return true;
2022        case TYPE_IMPLEMENTATION:   return true;
2023        case TYPE_NC_CLASS:         return true;
2024        case TYPE_ARRAY:            return true;
2025        case TYPE_JAVA_RMI_REMOTE:  return false;
2026
2027        default: throw new Error("unexpected type code: " + type.getTypeCode());
2028        }
2029    }
2030
2031    /*
2032     * Decide which arguments need to be copied and write
2033     * the copy code. Returns an array of argument names to
2034     * use to refer to either the copy or the original.
2035     */
2036    String[] writeCopyArguments(CompoundType.Method method,
2037                                IndentingWriter p) throws IOException {
2038
2039        Type[] args = method.getArguments();
2040        String[] origNames = method.getArgumentNames();
2041
2042        // Copy the current parameter names to a result array...
2043
2044        String[] result = new String[origNames.length];
2045        for (int i = 0; i < result.length; i++) {
2046            result[i] = origNames[i];
2047        }
2048
2049        // Decide which arguments must be copied, if any. If
2050        // any of the arguments are types for which a 'real' copy
2051        // will be done, rather than just an autoConnect, set
2052        // realCopy = true. Note that abstract types may only
2053        // need autoConnect, but we cannot know that at compile
2054        // time...
2055
2056        boolean realCopy = false;
2057        boolean[] copyArg = new boolean[args.length];
2058        int copyCount = 0;
2059        int firstCopiedArg = 0; // Only used in single copy case.  It is only the first arg that
2060                                // needs copying IF copyCount == 1.
2061
2062        for (int i = 0; i < args.length; i++) {
2063            if (mustCopy(args[i])) {
2064                copyArg[i] = true;
2065                copyCount++;
2066                firstCopiedArg = i;
2067                if (args[i].getTypeCode() != TYPE_REMOTE &&
2068                    args[i].getTypeCode() != TYPE_IMPLEMENTATION) {
2069                    realCopy = true;
2070                }
2071            } else {
2072                copyArg[i] = false;
2073            }
2074        }
2075
2076        // Do we have any types which must be copied?
2077        if (copyCount > 0) {
2078            // Yes. Are we only doing the copy to ensure
2079            // that autoConnect occurs?
2080            if (realCopy) {
2081                // Nope. We need to go back thru the list and
2082                // mark any strings so that they will be copied
2083                // to preserve any shared references...
2084                for (int i = 0; i < args.length; i++) {
2085                    if (args[i].getTypeCode() == TYPE_STRING) {
2086                        copyArg[i] = true;
2087                        copyCount++;
2088                    }
2089                }
2090            }
2091
2092            // We're ready to generate code. Do we have more than
2093            // one to copy?
2094            if (copyCount > 1) {
2095                // Generate a call to copyObjects...
2096                String arrayName = getVariableName("copies");
2097                p.p("Object[] " + arrayName + " = Util.copyObjects(new Object[]{");
2098                boolean first = true;
2099                for (int i = 0; i < args.length; i++) {
2100                    if (copyArg[i]) {
2101                        if (!first) {
2102                            p.p(",");
2103                        }
2104                        first = false;
2105                        p.p(origNames[i]);
2106                    }
2107                }
2108                p.pln("},_orb());");
2109
2110                // For each of the types which was copied, create
2111                // a local temporary for it, updating the result
2112                // array with the new local parameter name...
2113                int copyIndex = 0 ;
2114                for (int i = 0; i < args.length; i++) {
2115                    if (copyArg[i]) {
2116                        result[i] = getVariableName(result[i]+"Copy");
2117                        p.pln( getName(args[i]) + " " + result[i] + " = (" + getName(args[i]) + ") " +
2118                               arrayName + "[" + copyIndex++ +"];");
2119                    }
2120                }
2121            } else {
2122                // Generate a call to copyObject, updating the result
2123                // with the new local parameter name...
2124                result[firstCopiedArg] = getVariableName(result[firstCopiedArg]+"Copy");
2125                p.pln( getName(args[firstCopiedArg]) + " " + result[firstCopiedArg] + " = (" +
2126                       getName(args[firstCopiedArg]) + ") Util.copyObject(" +
2127                       origNames[firstCopiedArg] + ",_orb());");
2128            }
2129        }
2130
2131        return result;
2132    }
2133
2134    static final String SINGLE_SLASH = "\\";
2135    static final String DOUBLE_SLASH = SINGLE_SLASH + SINGLE_SLASH;
2136
2137    String getRepositoryID(Type type) {
2138        return IDLNames.replace(type.getRepositoryID(), SINGLE_SLASH, DOUBLE_SLASH);
2139    }
2140
2141    String getExceptionRepositoryID(Type type) {
2142        ClassType theType = (ClassType) type;
2143        return IDLNames.getIDLRepositoryID(theType.getQualifiedIDLExceptionName(false));
2144    }
2145
2146    String getVariableName(String proposed) {
2147        while (namesInUse.contains(proposed)) {
2148            proposed = "$" + proposed;
2149        }
2150
2151        return proposed;
2152    }
2153
2154    void addNamesInUse(CompoundType.Method[] methods) {
2155        for (int i = 0; i < methods.length; i++) {
2156            addNamesInUse(methods[i]);
2157        }
2158    }
2159
2160    void addNamesInUse(CompoundType.Method method) {
2161        String paramNames[] = method.getArgumentNames();
2162        for (int i = 0; i < paramNames.length; i++) {
2163            addNameInUse(paramNames[i]);
2164        }
2165    }
2166
2167    void addNameInUse(String name) {
2168        namesInUse.add(name);
2169    }
2170
2171    static boolean mustCopy(Type type) {
2172        switch (type.getTypeCode()) {
2173        case TYPE_VOID:
2174        case TYPE_BOOLEAN:
2175        case TYPE_BYTE:
2176        case TYPE_CHAR:
2177        case TYPE_SHORT:
2178        case TYPE_INT:
2179        case TYPE_LONG:
2180        case TYPE_FLOAT:
2181        case TYPE_DOUBLE:
2182        case TYPE_STRING:           return false;
2183
2184        case TYPE_ANY:              return true;
2185
2186        case TYPE_CORBA_OBJECT:     return false;
2187
2188        case TYPE_REMOTE:
2189        case TYPE_ABSTRACT:
2190        case TYPE_NC_INTERFACE:
2191        case TYPE_VALUE:
2192        case TYPE_IMPLEMENTATION:
2193        case TYPE_NC_CLASS:
2194        case TYPE_ARRAY:
2195        case TYPE_JAVA_RMI_REMOTE:  return true;
2196
2197        default: throw new Error("unexpected type code: " + type.getTypeCode());
2198        }
2199    }
2200
2201    ValueType[] getStubExceptions (CompoundType.Method method, boolean sort) {
2202
2203        ValueType[] list = method.getFilteredStubExceptions(method.getExceptions());
2204
2205        // Sort the list so that all org.omg.CORBA.UserException
2206        // subtypes are at the beginning of the list.  This ensures
2207        // that the stub will not call read_string() before calling
2208        // XXHelper.read().
2209
2210        if (sort) {
2211            Arrays.sort(list,new UserExceptionComparator());
2212            }
2213
2214        return list;
2215                }
2216
2217    ValueType[] getTieExceptions (CompoundType.Method method) {
2218        return method.getUniqueCatchList(method.getImplExceptions());
2219    }
2220
2221    void writeTieMethod(IndentingWriter p, CompoundType type,
2222                        CompoundType.Method method) throws IOException {
2223        String methodName = method.getName();
2224        Type paramTypes[] = method.getArguments();
2225        String paramNames[] = method.getArgumentNames();
2226        Type returnType = method.getReturnType();
2227        ValueType[] exceptions = getTieExceptions(method);
2228        String in = getVariableName("in");
2229        String ex = getVariableName("ex");
2230        String out = getVariableName("out");
2231        String reply = getVariableName("reply");
2232
2233        for (int i = 0; i < paramTypes.length; i++) {
2234            p.p(getName(paramTypes[i])+" "+paramNames[i]+" = ");
2235            writeUnmarshalArgument(p, in, paramTypes[i], null);
2236            p.pln();
2237        }
2238
2239        boolean handleExceptions = exceptions != null;
2240        boolean doReturn = !returnType.isType(TYPE_VOID);
2241
2242        if (handleExceptions && doReturn) {
2243            String objName = testUtil(getName(returnType), returnType);
2244            p.pln(objName+" result;");
2245        }
2246
2247        if (handleExceptions)
2248            p.plnI("try {");
2249
2250        if (doReturn) {
2251            if (handleExceptions) {
2252                p.p("result = ");
2253            } else {
2254                p.p(getName(returnType)+" result = ");
2255            }
2256        }
2257
2258        p.p("target."+methodName+"(");
2259        for(int i = 0; i < paramNames.length; i++) {
2260            if (i > 0)
2261                p.p(", ");
2262            p.p(paramNames[i]);
2263        }
2264        p.pln(");");
2265
2266        if (handleExceptions) {
2267            for(int i = 0; i < exceptions.length; i++) {
2268                p.pOlnI("} catch ("+getName(exceptions[i])+" "+ex+") {");
2269
2270                // Is this our IDLEntity Exception special case?
2271
2272                if (exceptions[i].isIDLEntityException() && !exceptions[i].isCORBAUserException()) {
2273
2274                                // Yes...
2275
2276                    String helperName = IDLNames.replace(exceptions[i].getQualifiedIDLName(false),"::",".");
2277                    helperName += "Helper";
2278                    p.pln(idOutputStream+" "+out +" = "+reply+".createExceptionReply();");
2279                    p.pln(helperName+".write("+out+","+ex+");");
2280
2281                } else {
2282
2283                                // No...
2284
2285                    p.pln("String id = \"" + getExceptionRepositoryID(exceptions[i]) + "\";");
2286                p.plnI(idExtOutputStream + " "+out+" = ");
2287                p.pln("(" + idExtOutputStream + ") "+reply+".createExceptionReply();");
2288                p.pOln(out+".write_string(id);");
2289                    p.pln(out+".write_value("+ex+"," + getName(exceptions[i]) + ".class);");
2290                }
2291
2292                p.pln("return "+out+";");
2293            }
2294            p.pOln("}");
2295        }
2296
2297        if (needNewWriteStreamClass(returnType)) {
2298            p.plnI(idExtOutputStream + " "+out+" = ");
2299            p.pln("(" + idExtOutputStream + ") "+reply+".createReply();");
2300            p.pO();
2301        } else {
2302            p.pln("OutputStream "+out+" = "+reply+".createReply();");
2303        }
2304
2305        if (doReturn) {
2306            writeMarshalArgument(p, out, returnType, "result");
2307            p.pln();
2308        }
2309
2310        p.pln("return "+out+";");
2311    }
2312
2313
2314    /**
2315     * Write Java statements to marshal a series of values in order as
2316     * named in the "names" array, with types as specified in the "types"
2317     * array", to the java.io.ObjectOutput stream named "stream".
2318     */
2319    void writeMarshalArguments(IndentingWriter p,
2320                               String streamName,
2321                               Type[] types, String[] names)
2322        throws IOException
2323    {
2324        if (types.length != names.length) {
2325            throw new Error("paramter type and name arrays different sizes");
2326        }
2327
2328        for (int i = 0; i < types.length; i++) {
2329            writeMarshalArgument(p, streamName, types[i], names[i]);
2330            if (i != types.length -1) {
2331                p.pln();
2332            }
2333        }
2334    }
2335
2336    /**
2337     * Added for IASRI 4987274. Remote classes named "Util" were
2338     * getting confused with javax.rmi.CORBA.Util and the
2339     * unqualifiedName "Util".
2340     */
2341    String testUtil(String objectName, Type ttype) {
2342        if (objectName.equals("Util")) {
2343                String correctedName = (String)ttype.getPackageName() + "." + objectName;
2344                return correctedName;
2345        } else {
2346                return objectName;
2347        }
2348    }
2349}
2350
2351class StringComparator implements java.util.Comparator {
2352    public int compare(Object o1, Object o2) {
2353        String s1 = (String)o1;
2354        String s2 = (String)o2;
2355        return s1.compareTo(s2);
2356    }
2357}
2358
2359
2360class UserExceptionComparator implements java.util.Comparator {
2361    public int compare(Object o1, Object o2) {
2362        ValueType v1 = (ValueType)o1;
2363        ValueType v2 = (ValueType)o2;
2364        int result = 0;
2365        if (isUserException(v1)) {
2366            if (!isUserException(v2)) {
2367                result = -1;
2368            }
2369        } else if (isUserException(v2)) {
2370            if (!isUserException(v1)) {
2371                result = 1;
2372            }
2373        }
2374        return result;
2375    }
2376
2377    final boolean isUserException(ValueType it) {
2378        return it.isIDLEntityException() && !it.isCORBAUserException();
2379    }
2380}
2381