--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/corba/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<argv.length; ctr++ ) {
+ if (argv[ctr].charAt(1) != '-') {
+ transactionalObjects.put( argv[ctr], marker ) ;
+ break ;
+ }
+ }
+ argv[i] = null;
+ } else if (arg.equals( "-poa" )) {
+ POATie = true ;
+ argv[i] = null;
+ }
+ }
+ }
+ }
+ if(POATie){
+ tieBaseClass = DEFAULT_POA_TIE_CLASS;
+ } else {
+ tieBaseClass = DEFAULT_TIE_CLASS;
+ }
+ return result;
+ }
+
+ /**
+ * Return an array containing all the file names and types that need to be
+ * generated for the given top-level type. The file names must NOT have an
+ * extension (e.g. ".java").
+ * @param topType The type returned by getTopType().
+ * @param alreadyChecked A set of Types which have already been checked.
+ * Intended to be passed to topType.collectMatching(filter,alreadyChecked).
+ */
+ protected OutputType[] getOutputTypesFor(CompoundType topType,
+ HashSet alreadyChecked) {
+
+ // We want to generate stubs for all remote and implementation types,
+ // so collect them up.
+ //
+ // We use the form of collectMatching which allows us to pass in a set of
+ // types which have previously been checked. By doing so, we ensure that if
+ // the command line contains Hello and HelloImpl, we will only generate
+ // output for Hello once...
+
+ int filter = TYPE_REMOTE | TYPE_IMPLEMENTATION;
+ Type[] genTypes = topType.collectMatching(filter,alreadyChecked);
+ int count = genTypes.length;
+ Vector list = new Vector(count+5);
+ BatchEnvironment theEnv = topType.getEnv();
+
+ // Now walk all types...
+
+ for (int i = 0; i < genTypes.length; i++) {
+
+ Type type = genTypes[i];
+ String typeName = type.getName();
+ boolean createStub = true;
+
+ // Is it an implementation type?
+
+ if (type instanceof ImplementationType) {
+
+ // Yes, so add a tie for it...
+
+ list.addElement(new OutputType(Utility.tieNameForCompiler(typeName), type));
+
+ // Does it have more than 1 remote interface? If so, we
+ // want to create a stub for it...
+
+ int remoteInterfaceCount = 0;
+ InterfaceType[] interfaces = ((CompoundType)type).getInterfaces();
+ for (int j = 0; j < interfaces.length; j++) {
+ if (interfaces[j].isType(TYPE_REMOTE) &&
+ !interfaces[j].isType(TYPE_ABSTRACT)) {
+ remoteInterfaceCount++;
+ }
+ }
+
+ if (remoteInterfaceCount <= 1) {
+
+ // No, so do not create a stub for this type...
+
+ createStub = false;
+ }
+ }
+
+ // Is it an abstract interface type?
+
+ if (type instanceof AbstractType) {
+
+ // Do not create a stub for this type...
+
+ createStub = false; // d11141
+ }
+
+ if (createStub) {
+
+ // Add a stub for the type...
+
+ list.addElement(new OutputType(Utility.stubNameForCompiler(typeName), type));
+ }
+ }
+
+ // Copy list into array..
+
+ OutputType[] outputTypes = new OutputType[list.size()];
+ list.copyInto(outputTypes);
+ return outputTypes;
+ }
+
+ /**
+ * Return the file name extension for the given file name (e.g. ".java").
+ * All files generated with the ".java" extension will be compiled. To
+ * change this behavior for ".java" files, override the compileJavaSourceFile
+ * method to return false.
+ * @param outputType One of the items returned by getOutputTypesFor(...)
+ */
+ protected String getFileNameExtensionFor(OutputType outputType) {
+ return SOURCE_FILE_EXTENSION;
+ }
+
+ /**
+ * Write the output for the given OutputFileName into the output stream.
+ * @param name One of the items returned by getOutputTypesFor(...)
+ * @param alreadyChecked A set of Types which have already been checked.
+ * Intended to be passed to Type.collectMatching(filter,alreadyChecked).
+ * @param writer The output stream.
+ */
+ protected void writeOutputFor( OutputType outputType,
+ HashSet alreadyChecked,
+ IndentingWriter writer) throws IOException {
+
+ String fileName = outputType.getName();
+ CompoundType theType = (CompoundType) outputType.getType();
+
+ // Are we doing a Stub or Tie?
+
+ if (fileName.endsWith(Utility.RMI_STUB_SUFFIX)) {
+
+ // Stub.
+
+ writeStub(outputType,writer);
+
+ } else {
+
+ // Tie
+
+ writeTie(outputType,writer);
+ }
+ }
+
+ /**
+ * Write a stub for the specified type.
+ */
+ protected void writeStub(OutputType outputType,
+ IndentingWriter p) throws IOException {
+
+ CompoundType theType = (CompoundType) outputType.getType();
+ RemoteType[] remoteInterfaces = getDirectRemoteInterfaces(theType);
+
+ // Write comment.
+
+ p.pln("// Stub class generated by rmic, do not edit.");
+ p.pln("// Contents subject to change without notice.");
+ p.pln();
+
+ // Set our standard classes...
+
+ setStandardClassesInUse(theType,true);
+
+ // Add classes for this type...
+
+ addClassesInUse(theType,remoteInterfaces);
+
+ // Write package and import statements...
+
+ writePackageAndImports(p);
+
+ // Declare the stub class; implement all remote interfaces.
+
+ p.p("public class " + currentClass);
+ p.p(" extends " + getName(stubBaseClass));
+ p.p(" implements ");
+ if (remoteInterfaces.length > 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();
+ }
+}