diff -r 000000000000 -r 55540e827aef src/share/classes/sun/rmi/rmic/iiop/StubGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/rmi/rmic/iiop/StubGenerator.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,2274 @@ +/* + * Portions Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * Licensed Materials - Property of IBM + * RMI-IIOP v1.0 + * Copyright IBM Corp. 1998 1999 All Rights Reserved + * + */ + +package sun.rmi.rmic.iiop; + +import java.io.File; +import java.io.IOException; +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; +import sun.tools.java.Identifier; +import sun.tools.java.ClassNotFound; +import sun.tools.java.ClassDefinition; +import sun.tools.java.ClassDeclaration; +import sun.tools.java.CompilerError; +import sun.rmi.rmic.IndentingWriter; +import java.util.HashSet; +import java.util.Arrays; +import com.sun.corba.se.impl.util.Utility; +import com.sun.corba.se.impl.util.PackagePrefixChecker; +import sun.rmi.rmic.Main; + +/** + * An IIOP stub/tie generator for rmic. + * + * @author Bryan Atsatt + * @author Anil Vijendran + * @author M. Mortazavi + */ + +public class StubGenerator extends sun.rmi.rmic.iiop.Generator { + + private static final String DEFAULT_STUB_CLASS = "javax.rmi.CORBA.Stub"; + private static final String DEFAULT_TIE_CLASS = "org.omg.CORBA_2_3.portable.ObjectImpl"; + private static final String DEFAULT_POA_TIE_CLASS = "org.omg.PortableServer.Servant"; + + protected boolean reverseIDs = false; + protected boolean localStubs = true; + protected boolean standardPackage = false; + protected boolean useHash = true; + protected String stubBaseClass = DEFAULT_STUB_CLASS; + protected String tieBaseClass = DEFAULT_TIE_CLASS; + protected HashSet namesInUse = new HashSet(); + protected Hashtable classesInUse = new Hashtable(); + protected Hashtable imports = new Hashtable(); + protected int importCount = 0; + protected String currentPackage = null; + protected String currentClass = null; + protected boolean castArray = false; + protected Hashtable transactionalObjects = new Hashtable() ; + protected boolean POATie = false ; + + /** + * Default constructor for Main to use. + */ + public StubGenerator() { + } + + /** + * Overridden in order to set the standardPackage flag. + */ + public void generate( + sun.rmi.rmic.BatchEnvironment env, + ClassDefinition cdef, File destDir) { + ((sun.rmi.rmic.iiop.BatchEnvironment)env). + setStandardPackage(standardPackage); + super.generate(env, cdef, destDir); + } + + /** + * Return true if a new instance should be created for each + * class on the command line. Subclasses which return true + * should override newInstance() to return an appropriately + * constructed instance. + */ + protected boolean requireNewInstance() { + return false; + } + + /** + * Return true if non-conforming types should be parsed. + * @param stack The context stack. + */ + protected boolean parseNonConforming(ContextStack stack) { + + // We let the environment setting decide so that + // another generator (e.g. IDLGenerator) can change + // it and we will just go with the flow... + + return stack.getEnv().getParseNonConforming(); + } + + /** + * Create and return a top-level type. + * @param cdef The top-level class definition. + * @param stack The context stack. + * @return The compound type or null if is non-conforming. + */ + protected CompoundType getTopType(ClassDefinition cdef, ContextStack stack) { + + CompoundType result = null; + + // Do we have an interface? + + if (cdef.isInterface()) { + + // Yes, so first try Abstract... + + result = AbstractType.forAbstract(cdef,stack,true); + + if (result == null) { + + // Then try Remote... + + result = RemoteType.forRemote(cdef,stack,false); + } + } else { + + // Not an interface, so try Implementation... + + result = ImplementationType.forImplementation(cdef,stack,false); + } + + return result; + } + + /** + * Examine and consume command line arguments. + * @param argv The command line arguments. Ignore null + * and unknown arguments. Set each consumed argument to null. + * @param error Report any errors using the main.error() methods. + * @return true if no errors, false otherwise. + */ + public boolean parseArgs(String argv[], Main main) { + Object marker = new Object() ; + + // Reset any cached options... + + reverseIDs = false; + localStubs = true; + useHash = true; + stubBaseClass = DEFAULT_STUB_CLASS; + // tieBaseClass = DEFAULT_TIE_CLASS; + transactionalObjects = new Hashtable() ; + + // Parse options... + + boolean result = super.parseArgs(argv,main); + if (result) { + for (int i = 0; i < argv.length; i++) { + if (argv[i] != null) { + String arg = argv[i].toLowerCase(); + if (arg.equals("-iiop")) { + argv[i] = null; + } else if (arg.equals("-xreverseids")) { + reverseIDs = true; + argv[i] = null; + } else if (arg.equals("-nolocalstubs")) { + localStubs = false; + argv[i] = null; + } else if (arg.equals("-xnohash")) { + useHash = false; + argv[i] = null; + } else if (argv[i].equals("-standardPackage")) { + standardPackage = true; + argv[i] = null; + } else if (arg.equals("-xstubbase")) { + argv[i] = null; + if (++i < argv.length && argv[i] != null && !argv[i].startsWith("-")) { + stubBaseClass = argv[i]; + argv[i] = null; + } else { + main.error("rmic.option.requires.argument", "-Xstubbase"); + result = false; + } + } else if (arg.equals("-xtiebase")) { + argv[i] = null; + if (++i < argv.length && argv[i] != null && !argv[i].startsWith("-")) { + tieBaseClass = argv[i]; + argv[i] = null; + } else { + main.error("rmic.option.requires.argument", "-Xtiebase"); + result = false; + } + } else if (arg.equals("-transactional" )) { + // Scan for the next non-flag argument. + // Assume that it is a class name and add it + // to the list of transactional classes. + for ( int ctr=i+1; ctr 0) { + for(int i = 0; i < remoteInterfaces.length; i++) { + if (i > 0) { + p.pln(","); + } + String objName = testUtil(getName(remoteInterfaces[i]), theType); + p.p(objName); + } + } + + // Add java.rmi.Remote if this type does not implement it. + // This allows stubs for Abstract interfaces to be treated + // uniformly... + + if (!implementsRemote(theType)) { + p.pln(","); + p.p(getName("java.rmi.Remote")); + } + + p.plnI(" {"); + p.pln(); + + // Write the ids... + + writeIds( p, theType, false ); + p.pln(); + + // Write the _ids() method... + + p.plnI("public String[] _ids() { "); + p.pln("return _type_ids;"); + p.pOln("}"); + + // Get all the methods and write each stub method... + + CompoundType.Method[] remoteMethods = theType.getMethods(); + int methodCount = remoteMethods.length; + if (methodCount > 0) { + boolean writeHeader = true; + for(int i = 0; i < methodCount; i++) { + if (!remoteMethods[i].isConstructor()) { + if (writeHeader) { + writeHeader = false; + } + p.pln(); + writeStubMethod(p, remoteMethods[i], theType); + } + } + } + + // Write the cast array hack... + + writeCastArray(p); + + p.pOln("}"); // end stub class + } + + void addClassInUse(String qualifiedName) { + String unqualifiedName = qualifiedName; + String packageName = null; + int index = qualifiedName.lastIndexOf('.'); + if (index > 0) { + unqualifiedName = qualifiedName.substring(index+1); + packageName = qualifiedName.substring(0,index); + } + addClassInUse(unqualifiedName,qualifiedName,packageName); + } + + void addClassInUse(Type type) { + if (!type.isPrimitive()) { + Identifier id = type.getIdentifier(); + String name = IDLNames.replace(id.getName().toString(),". ","."); + String packageName = type.getPackageName(); + String qualifiedName; + if (packageName != null) { + qualifiedName = packageName+"."+name; + } else { + qualifiedName = name; + } + addClassInUse(name,qualifiedName,packageName); + } + } + + void addClassInUse(Type[] types) { + for (int i = 0; i < types.length; i++) { + addClassInUse(types[i]); + } + } + + void addStubInUse(Type type) { + if (type.getIdentifier() != idCorbaObject && + type.isType(TYPE_CORBA_OBJECT)) { + String stubName = getStubNameFor(type,false); + String packageName = type.getPackageName(); + String fullName; + if (packageName == null) { + fullName = stubName; + } else { + fullName = packageName + "." + stubName; + } + addClassInUse(stubName,fullName,packageName); + } + if (type.isType(TYPE_REMOTE) || + type.isType(TYPE_JAVA_RMI_REMOTE)) { + addClassInUse("javax.rmi.PortableRemoteObject"); + } + } + + String getStubNameFor(Type type, boolean qualified) { + String stubName; + String className; + if (qualified) { + className = type.getQualifiedName(); + } else { + className = type.getName(); + } + if (((CompoundType)type).isCORBAObject()) { + stubName = Utility.idlStubName(className); + } else { + stubName = Utility.stubNameForCompiler(className); + } + return stubName; + } + + void addStubInUse(Type[] types) { + for (int i = 0; i < types.length; i++) { + addStubInUse(types[i]); + } + } + + private static final String NO_IMPORT = new String(); + + void addClassInUse(String unqualifiedName, String qualifiedName, String packageName) { + + // Have we already got an entry for this qualifiedName? + + String currentName = (String)classesInUse.get(qualifiedName); + + if (currentName == null) { + + // No, never seen it before. Grab any existing import + // name and then decide what to do... + + String importName = (String) imports.get(unqualifiedName); + String nameToUse = null; + + if (packageName == null) { + + // Default package, so doesn't matter which name to use... + + nameToUse = unqualifiedName; + + } else if (packageName.equals("java.lang")) { + + // java.lang.*, so use unqualified name... + + nameToUse = unqualifiedName; + + // unless you want to be able to import things from the right place :--) + + if(nameToUse.endsWith("_Stub")) nameToUse = Util.packagePrefix()+qualifiedName; + + } else if (currentPackage != null && packageName.equals(currentPackage)) { + + // Class in currentPackage, so use unqualified name... + + nameToUse = unqualifiedName; + + // Do we already have a previous import under this + // unqualified name? + + if (importName != null) { + + // Yes, so we use qualifiedName... + + nameToUse = qualifiedName; + + } + + } else if (importName != null) { + + // It is in some package for which we normally + // would import, but we have a previous import + // under this unqualified name. We must use + // the qualified name... + + nameToUse = qualifiedName; + + /* + // Is the currentPackage the default package? + + if (currentPackage == null) { + + // Yes, so undo the import so that all + // uses for this name will be qualified... + + String old = (String)imports.remove(unqualifiedName); + classesInUse.put(old,old); + importCount--; + + // Note that this name is in use but should + // not be imported... + + imports.put(nameToUse,NO_IMPORT); + } + */ + } else if (qualifiedName.equals("org.omg.CORBA.Object")) { + + // Always qualify this quy to avoid confusion... + + nameToUse = qualifiedName; + + } else { + + // Default to using unqualified name, and add + // this guy to the imports... + + // Check for nested class in which case we use + // the fully qualified name instead of imports + if (unqualifiedName.indexOf('.') != -1) { + nameToUse = qualifiedName; + } else { + nameToUse = unqualifiedName; + imports.put(unqualifiedName,qualifiedName); + importCount++; + } + } + + // Now add the name... + + classesInUse.put(qualifiedName,nameToUse); + } + } + + String getName(Type type) { + if (type.isPrimitive()) { + return type.getName() + type.getArrayBrackets(); + } + Identifier id = type.getIdentifier(); + String name = IDLNames.replace(id.toString(),". ","."); + return getName(name) + type.getArrayBrackets(); + } + + // Added for Bug 4818753 + String getExceptionName(Type type) { + Identifier id = type.getIdentifier(); + return IDLNames.replace(id.toString(),". ","."); + } + + String getName(String qualifiedName) { + return (String)classesInUse.get(qualifiedName); + } + + String getName(Identifier id) { + return getName(id.toString()); + } + + String getStubName(Type type) { + String stubName = getStubNameFor(type,true); + return getName(stubName); + } + + void setStandardClassesInUse(CompoundType type, + boolean stub) throws IOException { + + // Reset our state... + + currentPackage = type.getPackageName(); + imports.clear(); + classesInUse.clear(); + namesInUse.clear(); + importCount = 0; + castArray = false; + + // Add the top-level type... + + addClassInUse(type); + + // Set current class name... + + if (stub) { + currentClass = Utility.stubNameForCompiler(type.getName()); + } else { + currentClass = Utility.tieNameForCompiler(type.getName()); + } + + // Add current class... + + if (currentPackage == null) { + addClassInUse(currentClass,currentClass,currentPackage); + } else { + addClassInUse(currentClass,(currentPackage+"."+currentClass),currentPackage); + } + + // Add standard classes... + + addClassInUse("javax.rmi.CORBA.Util"); + addClassInUse(idRemote.toString()); + addClassInUse(idRemoteException.toString()); + addClassInUse(idOutputStream.toString()); + addClassInUse(idInputStream.toString()); + addClassInUse(idSystemException.toString()); + addClassInUse(idJavaIoSerializable.toString()); + addClassInUse(idCorbaORB.toString()); + addClassInUse(idReplyHandler.toString()); + + // Add stub/tie specific imports... + + if (stub) { + addClassInUse(stubBaseClass); + addClassInUse("java.rmi.UnexpectedException"); + addClassInUse(idRemarshalException.toString()); + addClassInUse(idApplicationException.toString()); + if (localStubs) { + addClassInUse("org.omg.CORBA.portable.ServantObject"); + } + } else { + addClassInUse(type); + addClassInUse(tieBaseClass); + addClassInUse(idTieInterface.toString()); + addClassInUse(idBadMethodException.toString()); + addClassInUse(idPortableUnknownException.toString()); + addClassInUse(idJavaLangThrowable.toString()); + } + } + + void addClassesInUse(CompoundType type, RemoteType[] interfaces) { + + // Walk all methods and add types in use... + + CompoundType.Method[] methods = type.getMethods(); + for (int i = 0; i < methods.length; i++) { + addClassInUse(methods[i].getReturnType()); + addStubInUse(methods[i].getReturnType()); + addClassInUse(methods[i].getArguments()); + addStubInUse(methods[i].getArguments()); + addClassInUse(methods[i].getExceptions()); + // bug 4473859: Also include narrower subtypes for use + addClassInUse(methods[i].getImplExceptions()); + } + + // If this is a stub, add all interfaces... + + if (interfaces != null) { + addClassInUse(interfaces); + } + } + + void writePackageAndImports(IndentingWriter p) throws IOException { + + // Write package declaration... + + if (currentPackage != null) { + p.pln("package " + + Util.correctPackageName( + currentPackage, false, standardPackage) + + ";"); + p.pln(); + } + + // Get imports into an array and sort them... + + String[] names = new String[importCount]; + int index = 0; + for (Enumeration e = imports.elements() ; e.hasMoreElements() ;) { + String it = (String) e.nextElement(); + if (it != NO_IMPORT) { + names[index++] = it; + } + } + + Arrays.sort(names,new StringComparator()); + + // Now dump them out... + + for (int i = 0; i < importCount; i++) { + if( + Util.isOffendingPackage(names[i]) + && names[i].endsWith("_Stub") + && String.valueOf(names[i].charAt(names[i].lastIndexOf(".")+1)).equals("_") + ){ + p.pln("import " + PackagePrefixChecker.packagePrefix()+names[i]+";"); + } else{ + p.pln("import " + names[i] + ";"); + } + } + p.pln(); + + // Include offending packages . . . + if ( currentPackage!=null && Util.isOffendingPackage(currentPackage) ){ + p.pln("import " + currentPackage +".* ;"); + } + p.pln(); + + } + + boolean implementsRemote(CompoundType theType) { + boolean result = theType.isType(TYPE_REMOTE) && !theType.isType(TYPE_ABSTRACT); + + // If theType is not remote, look at all the interfaces + // until we find one that is... + + if (!result) { + InterfaceType[] interfaces = theType.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + result = implementsRemote(interfaces[i]); + if (result) { + break; + } + } + } + + return result; + } + + void writeStubMethod ( IndentingWriter p, + CompoundType.Method method, + CompoundType theType) throws IOException { + + // Wtite the method declaration and opening brace... + + String methodName = method.getName(); + String methodIDLName = method.getIDLName(); + + Type paramTypes[] = method.getArguments(); + String paramNames[] = method.getArgumentNames(); + Type returnType = method.getReturnType(); + ValueType[] exceptions = getStubExceptions(method,false); + + addNamesInUse(method); + addNameInUse("_type_ids"); + + String objName = testUtil(getName(returnType), returnType); + p.p("public " + objName + " " + methodName + "("); + for(int i = 0; i < paramTypes.length; i++) { + if (i > 0) + p.p(", "); + p.p(getName(paramTypes[i]) + " " + paramNames[i]); + } + + p.p(")"); + if (exceptions.length > 0) { + p.p(" throws "); + for(int i = 0; i < exceptions.length; i++) { + if (i > 0) { + p.p(", "); + } + // Added for Bug 4818753 + p.p(getExceptionName(exceptions[i])); + } + } + + p.plnI(" {"); + + // Now create the method body... + + if (localStubs) { + writeLocalStubMethodBody(p,method,theType); + } else { + writeNonLocalStubMethodBody(p,method,theType); + } + + // Close out the method... + + p.pOln("}"); + } + + + void writeLocalStubMethodBody (IndentingWriter p, + CompoundType.Method method, + CompoundType theType) throws IOException { + + String objName; + String paramNames[] = method.getArgumentNames(); + Type returnType = method.getReturnType(); + ValueType[] exceptions = getStubExceptions(method,false); + String methodName = method.getName(); + String methodIDLName = method.getIDLName(); + + p.plnI("if (!Util.isLocal(this)) {"); + writeNonLocalStubMethodBody(p,method,theType); + p.pOlnI("} else {"); + String so = getVariableName("so"); + + p.pln("ServantObject "+so+" = _servant_preinvoke(\""+methodIDLName+"\","+getName(theType)+".class);"); + p.plnI("if ("+so+" == null) {"); + if (!returnType.isType(TYPE_VOID)) { + p.p("return "); + } + p.p(methodName+"("); + for (int i = 0; i < paramNames.length; i++) { + if (i > 0) + p.p(", "); + p.p(paramNames[i]); + } + p.pln(");"); + if (returnType.isType(TYPE_VOID)) { + p.pln( "return ;" ) ; + } + + p.pOln("}"); + p.plnI("try {"); + + // Generate code to copy required arguments, and + // get back the names by which all arguments are known... + + String[] argNames = writeCopyArguments(method,p); + + // Now write the method... + + boolean copyReturn = mustCopy(returnType); + String resultName = null; + if (!returnType.isType(TYPE_VOID)) { + if (copyReturn) { + resultName = getVariableName("result"); + objName = testUtil(getName(returnType), returnType); + p.p(objName+" "+resultName + " = "); + } else { + p.p("return "); + } + } + objName = testUtil(getName(theType), theType); + p.p("(("+objName+")"+so+".servant)."+methodName+"("); + + for (int i = 0; i < argNames.length; i++) { + if (i > 0) + p.p(", "); + p.p(argNames[i]); + } + + if (copyReturn) { + p.pln(");"); + objName = testUtil(getName(returnType), returnType); + p.pln("return ("+objName+")Util.copyObject("+resultName+",_orb());"); + } else { + p.pln(");"); + } + + String e1 = getVariableName("ex"); + String e2 = getVariableName("exCopy"); + p.pOlnI("} catch (Throwable "+e1+") {"); + + p.pln("Throwable "+e2+" = (Throwable)Util.copyObject("+e1+",_orb());"); + for(int i = 0; i < exceptions.length; i++) { + if (exceptions[i].getIdentifier() != idRemoteException && + exceptions[i].isType(TYPE_VALUE)) { + // Added for Bug 4818753 + p.plnI("if ("+e2+" instanceof "+getExceptionName(exceptions[i])+") {"); + p.pln("throw ("+getExceptionName(exceptions[i])+")"+e2+";"); + p.pOln("}"); + } + } + + p.pln("throw Util.wrapException("+e2+");"); + p.pOlnI("} finally {"); + p.pln("_servant_postinvoke("+so+");"); + p.pOln("}"); + p.pOln("}"); + } + + + void writeNonLocalStubMethodBody ( IndentingWriter p, + CompoundType.Method method, + CompoundType theType) throws IOException { + + String methodName = method.getName(); + String methodIDLName = method.getIDLName(); + + Type paramTypes[] = method.getArguments(); + String paramNames[] = method.getArgumentNames(); + Type returnType = method.getReturnType(); + ValueType[] exceptions = getStubExceptions(method,true); + + String in = getVariableName("in"); + String out = getVariableName("out"); + String ex = getVariableName("ex"); + + // Decide if we need to use the new streams for + // any of the read calls... + + boolean needNewReadStreamClass = false; + for (int i = 0; i < exceptions.length; i++) { + if (exceptions[i].getIdentifier() != idRemoteException && + exceptions[i].isType(TYPE_VALUE) && + needNewReadStreamClass(exceptions[i])) { + needNewReadStreamClass = true; + break; + } + } + if (!needNewReadStreamClass) { + for (int i = 0; i < paramTypes.length; i++) { + if (needNewReadStreamClass(paramTypes[i])) { + needNewReadStreamClass = true; + break; + } + } + } + if (!needNewReadStreamClass) { + needNewReadStreamClass = needNewReadStreamClass(returnType); + } + + // Decide if we need to use the new streams for + // any of the write calls... + + boolean needNewWriteStreamClass = false; + for (int i = 0; i < paramTypes.length; i++) { + if (needNewWriteStreamClass(paramTypes[i])) { + needNewWriteStreamClass = true; + break; + } + } + + // Now write the method, inserting casts where needed... + + p.plnI("try {"); + if (needNewReadStreamClass) { + p.pln(idExtInputStream + " "+in+" = null;"); + } else { + p.pln(idInputStream + " "+in+" = null;"); + } + p.plnI("try {"); + + String argStream = "null"; + + if (needNewWriteStreamClass) { + p.plnI(idExtOutputStream + " "+out+" = "); + p.pln("(" + idExtOutputStream + ")"); + p.pln("_request(\"" + methodIDLName + "\", true);"); + p.pO(); + } else { + p.pln("OutputStream "+out+" = _request(\"" + methodIDLName + "\", true);"); + } + + if (paramTypes.length > 0) { + writeMarshalArguments(p, out, paramTypes, paramNames); + p.pln(); + } + argStream = out; + + if (returnType.isType(TYPE_VOID)) { + p.pln("_invoke(" + argStream + ");" ); + } else { + if (needNewReadStreamClass) { + p.plnI(in+" = (" + idExtInputStream + ")_invoke(" + argStream + ");"); + p.pO(); + } else { + p.pln(in+" = _invoke(" + argStream + ");"); + } + p.p("return "); + writeUnmarshalArgument(p, in, returnType, null); + p.pln(); + } + + // Handle ApplicationException... + + p.pOlnI("} catch ("+getName(idApplicationException)+" "+ex+") {"); + if (needNewReadStreamClass) { + p.pln(in + " = (" + idExtInputStream + ") "+ex+".getInputStream();"); + } else { + p.pln(in + " = "+ex+".getInputStream();"); + } + + boolean idRead = false; + boolean idAllocated = false; + for(int i = 0; i < exceptions.length; i++) { + if (exceptions[i].getIdentifier() != idRemoteException) { + + // Is this our special-case IDLEntity exception? + + if (exceptions[i].isIDLEntityException() && !exceptions[i].isCORBAUserException()) { + + // Yes. + + if (!idAllocated && !idRead) { + p.pln("String $_id = "+ex+".getId();"); + idAllocated = true; + } + + String helperName = IDLNames.replace(exceptions[i].getQualifiedIDLName(false),"::","."); + helperName += "Helper"; + p.plnI("if ($_id.equals("+helperName+".id())) {"); + p.pln("throw "+helperName+".read("+in+");"); + + } else { + + // No. + + if (!idAllocated && !idRead) { + p.pln("String $_id = "+in+".read_string();"); + idAllocated = true; + idRead = true; + } else if (idAllocated && !idRead) { + p.pln("$_id = "+in+".read_string();"); + idRead = true; + } + p.plnI("if ($_id.equals(\""+getExceptionRepositoryID(exceptions[i])+"\")) {"); + // Added for Bug 4818753 + p.pln("throw ("+getExceptionName(exceptions[i])+") "+in+".read_value(" + getExceptionName(exceptions[i]) + ".class);"); + } + p.pOln("}"); + } + } + if (!idAllocated && !idRead) { + p.pln("String $_id = "+in+".read_string();"); + idAllocated = true; + idRead = true; + } else if (idAllocated && !idRead) { + p.pln("$_id = "+in+".read_string();"); + idRead = true; + } + p.pln("throw new UnexpectedException($_id);"); + + // Handle RemarshalException... + + p.pOlnI("} catch ("+getName(idRemarshalException)+" "+ex+") {"); + if (!returnType.isType(TYPE_VOID)) { + p.p("return "); + } + p.p(methodName + "("); + for(int i = 0; i < paramTypes.length; i++) { + if (i > 0) { + p.p(","); + } + p.p(paramNames[i]); + } + p.pln(");"); + + // Ensure that we release the reply... + + p.pOlnI("} finally {"); + p.pln("_releaseReply("+in+");"); + + p.pOln("}"); + + // Handle SystemException... + + p.pOlnI("} catch (SystemException "+ex+") {"); + p.pln("throw Util.mapSystemException("+ex+");"); + p.pOln("}"); + + // returnResult(p,returnType); + } + + void allocateResult (IndentingWriter p, + Type returnType) throws IOException { + if (!returnType.isType(TYPE_VOID)) { + String objName = testUtil(getName(returnType), returnType); + p.p(objName + " result = "); + } + } + + int getTypeCode(Type type) { + + int typeCode = type.getTypeCode(); + + // Handle late-breaking special case for + // abstract IDL entities... + + if ((type instanceof CompoundType) && + ((CompoundType)type).isAbstractBase()) { + typeCode = TYPE_ABSTRACT; + } + + return typeCode; + } + + + /** + * Write a snippet of Java code to marshal a value named "name" of + * type "type" to the java.io.ObjectOutput stream named "stream". + */ + void writeMarshalArgument(IndentingWriter p, + String streamName, + Type type, String name) throws IOException { + + int typeCode = getTypeCode(type); + + switch (typeCode) { + case TYPE_BOOLEAN: + p.p(streamName + ".write_boolean(" + name + ");"); + break; + case TYPE_BYTE: + p.p(streamName + ".write_octet(" + name + ");"); + break; + case TYPE_CHAR: + p.p(streamName + ".write_wchar(" + name + ");"); + break; + case TYPE_SHORT: + p.p(streamName + ".write_short(" + name + ");"); + break; + case TYPE_INT: + p.p(streamName + ".write_long(" + name + ");"); + break; + case TYPE_LONG: + p.p(streamName + ".write_longlong(" + name + ");"); + break; + case TYPE_FLOAT: + p.p(streamName + ".write_float(" + name + ");"); + break; + case TYPE_DOUBLE: + p.p(streamName + ".write_double(" + name + ");"); + break; + case TYPE_STRING: + p.p(streamName + ".write_value(" + name + "," + getName(type) + ".class);"); + break; + case TYPE_ANY: + p.p("Util.writeAny("+ streamName + "," + name + ");"); + break; + case TYPE_CORBA_OBJECT: + p.p(streamName + ".write_Object(" + name + ");"); + break; + case TYPE_REMOTE: + p.p("Util.writeRemoteObject("+ streamName + "," + name + ");"); + break; + case TYPE_ABSTRACT: + p.p("Util.writeAbstractObject("+ streamName + "," + name + ");"); + break; + case TYPE_NC_INTERFACE: + p.p(streamName + ".write_value((Serializable)" + name + "," + getName(type) + ".class);"); + break; + case TYPE_VALUE: + p.p(streamName + ".write_value(" + name + "," + getName(type) + ".class);"); + break; + case TYPE_IMPLEMENTATION: + p.p(streamName + ".write_value((Serializable)" + name + "," + getName(type) + ".class);"); + break; + case TYPE_NC_CLASS: + p.p(streamName + ".write_value((Serializable)" + name + "," + getName(type) + ".class);"); + break; + case TYPE_ARRAY: + castArray = true; + p.p(streamName + ".write_value(cast_array(" + name + ")," + getName(type) + ".class);"); + break; + case TYPE_JAVA_RMI_REMOTE: + p.p("Util.writeRemoteObject("+ streamName + "," + name + ");"); + break; + default: + throw new Error("unexpected type code: " + typeCode); + } + } + + /** + * Write a snippet of Java code to unmarshal a value of type "type" + * from the java.io.ObjectInput stream named "stream" into a variable + * named "name" (if "name" is null, the value in unmarshalled and + * discarded). + */ + void writeUnmarshalArgument(IndentingWriter p, + String streamName, + Type type, + String name) throws IOException { + + int typeCode = getTypeCode(type); + + if (name != null) { + p.p(name + " = "); + } + + switch (typeCode) { + case TYPE_BOOLEAN: + p.p(streamName + ".read_boolean();"); + break; + case TYPE_BYTE: + p.p(streamName + ".read_octet();"); + break; + case TYPE_CHAR: + p.p(streamName + ".read_wchar();"); + break; + case TYPE_SHORT: + p.p(streamName + ".read_short();"); + break; + case TYPE_INT: + p.p(streamName + ".read_long();"); + break; + case TYPE_LONG: + p.p(streamName + ".read_longlong();"); + break; + case TYPE_FLOAT: + p.p(streamName + ".read_float();"); + break; + case TYPE_DOUBLE: + p.p(streamName + ".read_double();"); + break; + case TYPE_STRING: + p.p("(String) " + streamName + ".read_value(" + getName(type) + ".class);"); + break; + case TYPE_ANY: + if (type.getIdentifier() != idJavaLangObject) { + p.p("(" + getName(type) + ") "); + } + p.p("Util.readAny(" + streamName + ");"); + break; + case TYPE_CORBA_OBJECT: + if (type.getIdentifier() == idCorbaObject) { + p.p("(" + getName(type) + ") " + streamName + ".read_Object();"); + } else { + p.p("(" + getName(type) + ") " + streamName + ".read_Object(" + getStubName(type) + ".class);"); + } + break; + case TYPE_REMOTE: + String objName = testUtil(getName(type), type); + p.p("(" + objName + ") " + + "PortableRemoteObject.narrow(" + streamName + ".read_Object(), " + objName + ".class);"); + break; + case TYPE_ABSTRACT: + p.p("(" + getName(type) + ") " + streamName + ".read_abstract_interface();"); + break; + case TYPE_NC_INTERFACE: + p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);"); + break; + case TYPE_VALUE: + p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);"); + break; + case TYPE_IMPLEMENTATION: + p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);"); + break; + case TYPE_NC_CLASS: + p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);"); + break; + case TYPE_ARRAY: + p.p("(" + getName(type) + ") " + streamName + ".read_value(" + getName(type) + ".class);"); + break; + case TYPE_JAVA_RMI_REMOTE: + p.p("(" + getName(type) + ") " + + "PortableRemoteObject.narrow(" + streamName + ".read_Object(), " + getName(type) + ".class);"); + // p.p("(" + getName(type) + ") " + streamName + ".read_Object(" + getStubName(type) + ".class);"); + break; + default: + throw new Error("unexpected type code: " + typeCode); + } + } + + /** + * Get a list of all the RepositoryIDs for interfaces + * implemented directly or indirectly by theType. In the + * case of an ImplementationType which implements 2 or + * more remote interfaces, this list will begin with the + * Identifier for the implementation (see section 5.9 in + * the Java -> IDL mapping). Ensures that the most derived + * type is first in the list because the IOR is generated + * using that entry in the _ids array. + */ + String[] getAllRemoteRepIDs (CompoundType theType) { + + String[] result; + + // Collect up all the (inherited) remote interfaces + // (ignores all the 'special' interfaces: Remote, + // Serializable, Externalizable)... + + Type[] types = collectAllRemoteInterfaces(theType); + + int length = types.length; + boolean haveImpl = theType instanceof ImplementationType; + InterfaceType[] interfaces = theType.getInterfaces(); + int remoteCount = countRemote(interfaces,false); + int offset = 0; + + // Do we have an implementation type that implements + // more than one remote interface? + + if (haveImpl && remoteCount > 1) { + + // Yes, so we need to insert it at the beginning... + + result = new String[length + 1]; + result[0] = getRepositoryID(theType); + offset = 1; + + } else { + + // No. + + result = new String[length]; + + // Here we need to ensure that the most derived + // interface ends up being first in the list. If + // there is only one, we're done. + + if (length > 1) { + + // First, decide what the most derived type is... + + String mostDerived = null; + + if (haveImpl) { + + // If we get here, we know that there is only one + // direct remote interface, so just find it... + + for (int i = 0; i < interfaces.length; i++) { + if (interfaces[i].isType(TYPE_REMOTE)) { + mostDerived = interfaces[i].getRepositoryID(); + break; + } + } + } else { + + // If we get here we know that theType is a RemoteType + // so just use its id... + + mostDerived = theType.getRepositoryID(); + } + + // Now search types list and make sure mostDerived is + // at index zero... + + for (int i = 0; i < length; i++) { + if (types[i].getRepositoryID() == mostDerived) { + + // Found it. Swap it if we need to... + + if (i > 0) { + Type temp = types[0]; + types[0] = types[i]; + types[i] = temp; + } + + break; + } + } + } + } + + // Now copy contents of the types array... + + for (int i = 0; i < types.length; i++) { + result[offset++] = getRepositoryID(types[i]); + } + + // If we're supposed to, reverse the array. This + // is only done when the -testReverseIDs flag is + // passed, and that should ONLY be done for test + // cases. This is an undocumented feature. + + if (reverseIDs) { + int start = 0; + int end = result.length -1; + while (start < end) { + String temp = result[start]; + result[start++] = result[end]; + result[end--] = temp; + } + } + + return result; + } + + /** + * Collect all the inherited remote interfaces. + */ + Type[] collectAllRemoteInterfaces (CompoundType theType) { + Vector list = new Vector(); + + // Collect up all the Remote interfaces, and get an instance + // for java.rmi.Remote... + + addRemoteInterfaces(list,theType); + + // Create and return our results... + + Type[] result = new Type[list.size()]; + list.copyInto(result); + + return result; + } + + /** + * Add all the inherited remote interfaces to list. + */ + void addRemoteInterfaces(Vector list, CompoundType theType) { + + if (theType != null) { + if (theType.isInterface() && !list.contains(theType)) { + list.addElement(theType); + } + + InterfaceType[] interfaces = theType.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + + if (interfaces[i].isType(TYPE_REMOTE)) { + addRemoteInterfaces(list,interfaces[i]); + } + } + + addRemoteInterfaces(list,theType.getSuperclass()); + } + } + + /** + * Get a list of all the remote interfaces which this stub + * should declare. + */ + RemoteType[] getDirectRemoteInterfaces (CompoundType theType) { + + RemoteType[] result; + InterfaceType[] interfaces = theType.getInterfaces(); + + // First, get a list of all the interfaces... + + InterfaceType[] list; + + // Because we can be passed either an ImplementationType + // (which has interfaces) or a RemoteType (which is an + // interface and may have interfaces) we must handle each + // separately... + + // Do we have an implementation type? + + if (theType instanceof ImplementationType) { + + // Yes, so list is exactly what this type + // implements and is correct already. + + list = interfaces; + + } else { + + // No, so list is just theType... + + list = new InterfaceType[1]; + list[0] = (InterfaceType) theType; + } + + // Ok, now count up the remote interfaces, allocate + // our result and fill it in... + + int remoteCount = countRemote(list,false); + + if (remoteCount == 0) { + throw new CompilerError("iiop.StubGenerator: No remote interfaces!"); + } + + result = new RemoteType[remoteCount]; + int offset = 0; + for (int i = 0; i < list.length; i++) { + if (list[i].isType(TYPE_REMOTE)) { + result[offset++] = (RemoteType)list[i]; + } + } + + return result; + } + + int countRemote (Type[] list, boolean includeAbstract) { + int remoteCount = 0; + for (int i = 0; i < list.length; i++) { + if (list[i].isType(TYPE_REMOTE) && + (includeAbstract || !list[i].isType(TYPE_ABSTRACT))) { + remoteCount++; + } + } + + return remoteCount; + } + + void writeCastArray(IndentingWriter p) throws IOException { + if (castArray) { + p.pln(); + p.pln("// This method is required as a work-around for"); + p.pln("// a bug in the JDK 1.1.6 verifier."); + p.pln(); + p.plnI("private "+getName(idJavaIoSerializable)+" cast_array(Object obj) {"); + p.pln("return ("+getName(idJavaIoSerializable)+")obj;"); + p.pOln("}"); + } + } + void writeIds(IndentingWriter p, CompoundType theType, boolean isTie + ) throws IOException { + p.plnI("private static final String[] _type_ids = {"); + + String[] ids = getAllRemoteRepIDs(theType); + + if (ids.length >0 ) { + for(int i = 0; i < ids.length; i++) { + if (i > 0) + p.pln(", "); + p.p("\"" + ids[i] + "\""); + } + } else { + // Must be an implementation which only implements Remote... + p.pln("\"\""); + } + String qname = theType.getQualifiedName() ; + boolean isTransactional = isTie && transactionalObjects.containsKey( qname ) ; + // Add TransactionalObject if needed. + if (isTransactional) { + // Have already written an id. + p.pln( ", " ) ; + p.pln( "\"IDL:omg.org/CosTransactions/TransactionalObject:1.0\"" ) ; + } else if (ids.length > 0) { + p.pln(); + } + p.pOln("};"); + } + + + /** + * Write the Tie for the remote class to a stream. + */ + protected void writeTie(OutputType outputType, + IndentingWriter p) throws IOException + { + CompoundType theType = (CompoundType) outputType.getType(); + RemoteType[] remoteInterfaces = null; + + // Write comment... + p.pln("// Tie class generated by rmic, do not edit."); + p.pln("// Contents subject to change without notice."); + p.pln(); + + // Set our standard classes... + setStandardClassesInUse(theType,false); + + // Add classes for this type... + addClassesInUse(theType,remoteInterfaces); + + // Write package and import statements... + writePackageAndImports(p); + + // Declare the tie class. + p.p("public class " + currentClass + " extends " + + getName(tieBaseClass) + " implements Tie"); + + // Add java.rmi.Remote if this type does not implement it. + // This allows stubs for Abstract interfaces to be treated + // uniformly... + if (!implementsRemote(theType)) { + p.pln(","); + p.p(getName("java.rmi.Remote")); + } + + p.plnI(" {"); + + // Write data members... + p.pln(); + p.pln("private " + getName(theType) + " target = null;"); + p.pln(); + + // Write the ids... + writeIds( p, theType, true ) ; + + // Write setTarget method... + p.pln(); + p.plnI("public void setTarget(Remote target) {"); + p.pln("this.target = (" + getName(theType) + ") target;"); + p.pOln("}"); + + // Write getTarget method... + p.pln(); + p.plnI("public Remote getTarget() {"); + p.pln("return target;"); + p.pOln("}"); + + // Write thisObject method... + p.pln(); + write_tie_thisObject_method(p,idCorbaObject); + + // Write deactivate method... + p.pln(); + write_tie_deactivate_method(p); + + // Write get orb method... + p.pln(); + p.plnI("public ORB orb() {"); + p.pln("return _orb();"); + p.pOln("}"); + + // Write set orb method... + p.pln(); + write_tie_orb_method(p); + + // Write the _ids() method... + p.pln(); + write_tie__ids_method(p); + + // Get all the methods... + CompoundType.Method[] remoteMethods = theType.getMethods(); + + // Register all the argument names used, plus our + // data member names... + + addNamesInUse(remoteMethods); + addNameInUse("target"); + addNameInUse("_type_ids"); + + // Write the _invoke method... + p.pln(); + + String in = getVariableName("in"); + String _in = getVariableName("_in"); + String ex = getVariableName("ex"); + String method = getVariableName("method"); + String reply = getVariableName("reply"); + + p.plnI("public OutputStream _invoke(String "+method+", InputStream "+_in+", " + + "ResponseHandler "+reply+") throws SystemException {"); + + if (remoteMethods.length > 0) { + p.plnI("try {"); + p.plnI(idExtInputStream + " "+in+" = "); + p.pln("(" + idExtInputStream + ") "+_in+";"); + p.pO(); + + // See if we should use a hash table style + // comparison... + + StaticStringsHash hash = getStringsHash(remoteMethods); + + if (hash != null) { + p.plnI("switch ("+method+"."+hash.method+") {"); + for (int i = 0; i < hash.buckets.length; i++) { + p.plnI("case "+hash.keys[i]+": "); + for (int j = 0; j < hash.buckets[i].length; j++) { + CompoundType.Method current = remoteMethods[hash.buckets[i][j]]; + if (j > 0) { + p.pO("} else "); + } + p.plnI("if ("+method+".equals(\""+ current.getIDLName() +"\")) {"); + writeTieMethod(p, theType,current); + } + p.pOln("}"); + p.pO(); + } + } else { + for(int i = 0; i < remoteMethods.length; i++) { + CompoundType.Method current = remoteMethods[i]; + if (i > 0) { + p.pO("} else "); + } + + p.plnI("if ("+method+".equals(\""+ current.getIDLName() +"\")) {"); + writeTieMethod(p, theType, current); + } + } + + if (hash != null) { + p.pI(); + // p.plnI("default:"); + } else { + // p.pOlnI("} else {"); + } + // p.pln("throw new "+getName(idBadMethodException)+"();"); + + if (hash != null) { + p.pO(); + } + p.pOln("}"); + p.pln("throw new "+getName(idBadMethodException)+"();"); + + p.pOlnI("} catch ("+getName(idSystemException)+" "+ex+") {"); + p.pln("throw "+ex+";"); + + p.pOlnI("} catch ("+getName(idJavaLangThrowable)+" "+ex+") {"); + p.pln("throw new " + getName(idPortableUnknownException) + "("+ex+");"); + p.pOln("}"); + } else { + // No methods... + + p.pln("throw new " + getName(idBadMethodException) + "();"); + } + + p.pOln("}"); // end invoke + + // Write the cast array hack... + + writeCastArray(p); + + // End tie class... + p.pOln("}"); + } + public void catchWrongPolicy(IndentingWriter p) throws IOException { + p.pln(""); + } + public void catchServantNotActive(IndentingWriter p) throws IOException { + p.pln(""); + } + public void catchObjectNotActive(IndentingWriter p) throws IOException { + p.pln(""); + } + + public void write_tie_thisObject_method(IndentingWriter p, + Identifier idCorbaObject) + throws IOException + { + if(POATie){ + p.plnI("public " + idCorbaObject + " thisObject() {"); + /* + p.pln("org.omg.CORBA.Object objref = null;"); + p.pln("try{"); + p.pln("objref = _poa().servant_to_reference(this);"); + p.pln("}catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){"); + catchWrongPolicy(p); + p.pln("}catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){"); + catchServantNotActive(p); + p.pln("}"); + p.pln("return objref;"); + */ + p.pln("return _this_object();"); + p.pOln("}"); + } else { + p.plnI("public " + idCorbaObject + " thisObject() {"); + p.pln("return this;"); + p.pOln("}"); + } + } + + public void write_tie_deactivate_method(IndentingWriter p) + throws IOException + { + if(POATie){ + p.plnI("public void deactivate() {"); + p.pln("try{"); + p.pln("_poa().deactivate_object(_poa().servant_to_id(this));"); + p.pln("}catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){"); + catchWrongPolicy(p); + p.pln("}catch (org.omg.PortableServer.POAPackage.ObjectNotActive exception){"); + catchObjectNotActive(p); + p.pln("}catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){"); + catchServantNotActive(p); + p.pln("}"); + p.pOln("}"); + } else { + p.plnI("public void deactivate() {"); + p.pln("_orb().disconnect(this);"); + p.pln("_set_delegate(null);"); + p.pln("target = null;"); + p.pOln("}"); + } + } + + public void write_tie_orb_method(IndentingWriter p) + throws IOException + { + if(POATie){ + p.plnI("public void orb(ORB orb) {"); + /* + p.pln("try{"); + p.pln("orb.connect(_poa().servant_to_reference(this));"); + p.pln("}catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){"); + catchWrongPolicy(p); + p.pln("}catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){"); + catchServantNotActive(p); + p.pln("}"); + */ + p.pln("try {"); + p.pln(" ((org.omg.CORBA_2_3.ORB)orb).set_delegate(this);"); + p.pln("}"); + p.pln("catch(ClassCastException e) {"); + p.pln(" throw new org.omg.CORBA.BAD_PARAM"); + p.pln(" (\"POA Servant requires an instance of org.omg.CORBA_2_3.ORB\");"); + p.pln("}"); + p.pOln("}"); + } else { + p.plnI("public void orb(ORB orb) {"); + p.pln("orb.connect(this);"); + p.pOln("}"); + } + } + + public void write_tie__ids_method(IndentingWriter p) + throws IOException + { + if(POATie){ + p.plnI("public String[] _all_interfaces(org.omg.PortableServer.POA poa, byte[] objectId){"); + p.pln("return _type_ids;"); + p.pOln("}"); + } else { + p.plnI("public String[] _ids() { "); + p.pln("return _type_ids;"); + p.pOln("}"); + } + } + + + StaticStringsHash getStringsHash (CompoundType.Method[] methods) { + if (useHash && methods.length > 1) { + String[] methodNames = new String[methods.length]; + for (int i = 0; i < methodNames.length; i++) { + methodNames[i] = methods[i].getIDLName(); + } + return new StaticStringsHash(methodNames); + } + return null; + } + + static boolean needNewReadStreamClass(Type type) { + if (type.isType(TYPE_ABSTRACT)) { + return true; + } + // Handle late-breaking special case for + // abstract IDL entities... + if ((type instanceof CompoundType) && + ((CompoundType)type).isAbstractBase()) { + return true; + } + return needNewWriteStreamClass(type); + } + + static boolean needNewWriteStreamClass(Type type) { + switch (type.getTypeCode()) { + case TYPE_VOID: + case TYPE_BOOLEAN: + case TYPE_BYTE: + case TYPE_CHAR: + case TYPE_SHORT: + case TYPE_INT: + case TYPE_LONG: + case TYPE_FLOAT: + case TYPE_DOUBLE: return false; + + case TYPE_STRING: return true; + case TYPE_ANY: return false; + case TYPE_CORBA_OBJECT: return false; + case TYPE_REMOTE: return false; + case TYPE_ABSTRACT: return false; + case TYPE_NC_INTERFACE: return true; + case TYPE_VALUE: return true; + case TYPE_IMPLEMENTATION: return true; + case TYPE_NC_CLASS: return true; + case TYPE_ARRAY: return true; + case TYPE_JAVA_RMI_REMOTE: return false; + + default: throw new Error("unexpected type code: " + type.getTypeCode()); + } + } + + /* + * Decide which arguments need to be copied and write + * the copy code. Returns an array of argument names to + * use to refer to either the copy or the original. + */ + String[] writeCopyArguments(CompoundType.Method method, + IndentingWriter p) throws IOException { + + Type[] args = method.getArguments(); + String[] origNames = method.getArgumentNames(); + + // Copy the current parameter names to a result array... + + String[] result = new String[origNames.length]; + for (int i = 0; i < result.length; i++) { + result[i] = origNames[i]; + } + + // Decide which arguments must be copied, if any. If + // any of the arguments are types for which a 'real' copy + // will be done, rather than just an autoConnect, set + // realCopy = true. Note that abstract types may only + // need autoConnect, but we cannot know that at compile + // time... + + boolean realCopy = false; + boolean[] copyArg = new boolean[args.length]; + int copyCount = 0; + int firstCopiedArg = 0; // Only used in single copy case. It is only the first arg that + // needs copying IF copyCount == 1. + + for (int i = 0; i < args.length; i++) { + if (mustCopy(args[i])) { + copyArg[i] = true; + copyCount++; + firstCopiedArg = i; + if (args[i].getTypeCode() != TYPE_REMOTE && + args[i].getTypeCode() != TYPE_IMPLEMENTATION) { + realCopy = true; + } + } else { + copyArg[i] = false; + } + } + + // Do we have any types which must be copied? + if (copyCount > 0) { + // Yes. Are we only doing the copy to ensure + // that autoConnect occurs? + if (realCopy) { + // Nope. We need to go back thru the list and + // mark any strings so that they will be copied + // to preserve any shared references... + for (int i = 0; i < args.length; i++) { + if (args[i].getTypeCode() == TYPE_STRING) { + copyArg[i] = true; + copyCount++; + } + } + } + + // We're ready to generate code. Do we have more than + // one to copy? + if (copyCount > 1) { + // Generate a call to copyObjects... + String arrayName = getVariableName("copies"); + p.p("Object[] " + arrayName + " = Util.copyObjects(new Object[]{"); + boolean first = true; + for (int i = 0; i < args.length; i++) { + if (copyArg[i]) { + if (!first) { + p.p(","); + } + first = false; + p.p(origNames[i]); + } + } + p.pln("},_orb());"); + + // For each of the types which was copied, create + // a local temporary for it, updating the result + // array with the new local parameter name... + int copyIndex = 0 ; + for (int i = 0; i < args.length; i++) { + if (copyArg[i]) { + result[i] = getVariableName(result[i]+"Copy"); + p.pln( getName(args[i]) + " " + result[i] + " = (" + getName(args[i]) + ") " + + arrayName + "[" + copyIndex++ +"];"); + } + } + } else { + // Generate a call to copyObject, updating the result + // with the new local parameter name... + result[firstCopiedArg] = getVariableName(result[firstCopiedArg]+"Copy"); + p.pln( getName(args[firstCopiedArg]) + " " + result[firstCopiedArg] + " = (" + + getName(args[firstCopiedArg]) + ") Util.copyObject(" + + origNames[firstCopiedArg] + ",_orb());"); + } + } + + return result; + } + + static final String SINGLE_SLASH = "\\"; + static final String DOUBLE_SLASH = SINGLE_SLASH + SINGLE_SLASH; + + String getRepositoryID(Type type) { + return IDLNames.replace(type.getRepositoryID(), SINGLE_SLASH, DOUBLE_SLASH); + } + + String getExceptionRepositoryID(Type type) { + ClassType theType = (ClassType) type; + return IDLNames.getIDLRepositoryID(theType.getQualifiedIDLExceptionName(false)); + } + + String getVariableName(String proposed) { + while (namesInUse.contains(proposed)) { + proposed = "$" + proposed; + } + + return proposed; + } + + void addNamesInUse(CompoundType.Method[] methods) { + for (int i = 0; i < methods.length; i++) { + addNamesInUse(methods[i]); + } + } + + void addNamesInUse(CompoundType.Method method) { + String paramNames[] = method.getArgumentNames(); + for (int i = 0; i < paramNames.length; i++) { + addNameInUse(paramNames[i]); + } + } + + void addNameInUse(String name) { + namesInUse.add(name); + } + + static boolean mustCopy(Type type) { + switch (type.getTypeCode()) { + case TYPE_VOID: + case TYPE_BOOLEAN: + case TYPE_BYTE: + case TYPE_CHAR: + case TYPE_SHORT: + case TYPE_INT: + case TYPE_LONG: + case TYPE_FLOAT: + case TYPE_DOUBLE: + case TYPE_STRING: return false; + + case TYPE_ANY: return true; + + case TYPE_CORBA_OBJECT: return false; + + case TYPE_REMOTE: + case TYPE_ABSTRACT: + case TYPE_NC_INTERFACE: + case TYPE_VALUE: + case TYPE_IMPLEMENTATION: + case TYPE_NC_CLASS: + case TYPE_ARRAY: + case TYPE_JAVA_RMI_REMOTE: return true; + + default: throw new Error("unexpected type code: " + type.getTypeCode()); + } + } + + ValueType[] getStubExceptions (CompoundType.Method method, boolean sort) { + + ValueType[] list = method.getFilteredStubExceptions(method.getExceptions()); + + // Sort the list so that all org.omg.CORBA.UserException + // subtypes are at the beginning of the list. This ensures + // that the stub will not call read_string() before calling + // XXHelper.read(). + + if (sort) { + Arrays.sort(list,new UserExceptionComparator()); + } + + return list; + } + + ValueType[] getTieExceptions (CompoundType.Method method) { + return method.getUniqueCatchList(method.getImplExceptions()); + } + + void writeTieMethod(IndentingWriter p, CompoundType type, + CompoundType.Method method) throws IOException { + String methodName = method.getName(); + Type paramTypes[] = method.getArguments(); + String paramNames[] = method.getArgumentNames(); + Type returnType = method.getReturnType(); + ValueType[] exceptions = getTieExceptions(method); + String in = getVariableName("in"); + String ex = getVariableName("ex"); + String out = getVariableName("out"); + String reply = getVariableName("reply"); + + for (int i = 0; i < paramTypes.length; i++) { + p.p(getName(paramTypes[i])+" "+paramNames[i]+" = "); + writeUnmarshalArgument(p, in, paramTypes[i], null); + p.pln(); + } + + boolean handleExceptions = exceptions != null; + boolean doReturn = !returnType.isType(TYPE_VOID); + + if (handleExceptions && doReturn) { + String objName = testUtil(getName(returnType), returnType); + p.pln(objName+" result;"); + } + + if (handleExceptions) + p.plnI("try {"); + + if (doReturn) { + if (handleExceptions) { + p.p("result = "); + } else { + p.p(getName(returnType)+" result = "); + } + } + + p.p("target."+methodName+"("); + for(int i = 0; i < paramNames.length; i++) { + if (i > 0) + p.p(", "); + p.p(paramNames[i]); + } + p.pln(");"); + + if (handleExceptions) { + for(int i = 0; i < exceptions.length; i++) { + p.pOlnI("} catch ("+getName(exceptions[i])+" "+ex+") {"); + + // Is this our IDLEntity Exception special case? + + if (exceptions[i].isIDLEntityException() && !exceptions[i].isCORBAUserException()) { + + // Yes... + + String helperName = IDLNames.replace(exceptions[i].getQualifiedIDLName(false),"::","."); + helperName += "Helper"; + p.pln(idOutputStream+" "+out +" = "+reply+".createExceptionReply();"); + p.pln(helperName+".write("+out+","+ex+");"); + + } else { + + // No... + + p.pln("String id = \"" + getExceptionRepositoryID(exceptions[i]) + "\";"); + p.plnI(idExtOutputStream + " "+out+" = "); + p.pln("(" + idExtOutputStream + ") "+reply+".createExceptionReply();"); + p.pOln(out+".write_string(id);"); + p.pln(out+".write_value("+ex+"," + getName(exceptions[i]) + ".class);"); + } + + p.pln("return "+out+";"); + } + p.pOln("}"); + } + + if (needNewWriteStreamClass(returnType)) { + p.plnI(idExtOutputStream + " "+out+" = "); + p.pln("(" + idExtOutputStream + ") "+reply+".createReply();"); + p.pO(); + } else { + p.pln("OutputStream "+out+" = "+reply+".createReply();"); + } + + if (doReturn) { + writeMarshalArgument(p, out, returnType, "result"); + p.pln(); + } + + p.pln("return "+out+";"); + } + + + /** + * Write Java statements to marshal a series of values in order as + * named in the "names" array, with types as specified in the "types" + * array", to the java.io.ObjectOutput stream named "stream". + */ + void writeMarshalArguments(IndentingWriter p, + String streamName, + Type[] types, String[] names) + throws IOException + { + if (types.length != names.length) { + throw new Error("paramter type and name arrays different sizes"); + } + + for (int i = 0; i < types.length; i++) { + writeMarshalArgument(p, streamName, types[i], names[i]); + if (i != types.length -1) { + p.pln(); + } + } + } + + /** + * Added for IASRI 4987274. Remote classes named "Util" were + * getting confused with javax.rmi.CORBA.Util and the + * unqualifiedName "Util". + */ + String testUtil(String objectName, Type ttype) { + if (objectName.equals("Util")) { + String correctedName = (String)ttype.getPackageName() + "." + objectName; + return correctedName; + } else { + return objectName; + } + } +} + +class StringComparator implements java.util.Comparator { + public int compare(Object o1, Object o2) { + String s1 = (String)o1; + String s2 = (String)o2; + return s1.compareTo(s2); + } +} + + +class UserExceptionComparator implements java.util.Comparator { + public int compare(Object o1, Object o2) { + ValueType v1 = (ValueType)o1; + ValueType v2 = (ValueType)o2; + int result = 0; + if (isUserException(v1)) { + if (!isUserException(v2)) { + result = -1; + } + } else if (isUserException(v2)) { + if (!isUserException(v1)) { + result = 1; + } + } + return result; + } + + final boolean isUserException(ValueType it) { + return it.isIDLEntityException() && !it.isCORBAUserException(); + } +}