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