blob: 132361c0cded6aa113a1c26b64186aa14c0cc7b0 [file] [log] [blame]
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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.io.SerializablePermission;
import java.security.AccessController;
import java.security.PrivilegedAction;
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 ;
protected boolean emitPermissionCheck = 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 (argv[i].equals("-emitPermissionCheck")) {
emitPermissionCheck = 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);
// generate
// import java.security.AccessController;
// import java.security.PrivilegedAction;
// import java.io.SerializablePermission;
if (emitPermissionCheck) {
p.pln("import java.security.AccessController;");
p.pln("import java.security.PrivilegedAction;");
p.pln("import java.io.SerializablePermission;");
p.pln();
p.pln();
}
// 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();
if (emitPermissionCheck) {
// produce the following generated code for example
//
// private transient boolean _instantiated = false;
//
// private static Void checkPermission() {
// SecurityManager sm = System.getSecurityManager();
// if (sm != null) {
// sm.checkPermission(new SerializablePermission(
// "enableSubclassImplementation")); // testing
// }
// return null;
// }
//
// private _XXXXX_Stub(Void ignore) {
// }
//
// public _XXXXX_Stub() {
// this(checkPermission());
// _instantiated = true;
// }
//
// private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
// checkPermission();
// s.defaultReadObject();
// _instantiated = true;
// }
//
// where XXXXX is the name of the remote interface
p.pln();
p.plnI("private transient boolean _instantiated = false;");
p.pln();
p.pO();
p.plnI("private static Void checkPermission() {");
p.plnI("SecurityManager sm = System.getSecurityManager();");
p.pln("if (sm != null) {");
p.pI();
p.plnI("sm.checkPermission(new SerializablePermission(");
p.plnI("\"enableSubclassImplementation\"));");
p.pO();
p.pO();
p.pOln("}");
p.pln("return null;");
p.pO();
p.pOln("}");
p.pln();
p.pO();
p.pI();
p.plnI("private " + currentClass + "(Void ignore) { }");
p.pln();
p.pO();
p.plnI("public " + currentClass + "() {");
p.pln("this(checkPermission());");
p.pln("_instantiated = true;");
p.pOln("}");
p.pln();
p.plnI("private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {");
p.plnI("checkPermission();");
p.pO();
p.pln("s.defaultReadObject();");
p.pln("_instantiated = true;");
p.pOln("}");
p.pln();
//p.pO();
}
if (!emitPermissionCheck) {
p.pI();
}
// Write the _ids() method...
p.plnI("public String[] _ids() { ");
p.pln("return (String[]) _type_ids.clone();");
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);
boolean hasIOException = 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 (emitPermissionCheck) {
p.pln("if ((System.getSecurityManager() != null) && (!_instantiated)) {");
p.plnI(" throw new java.io.IOError(new java.io.IOException(\"InvalidObject \"));");
p.pOln("}");
p.pln();
}
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("volatile 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.pln(getName(theType) + " target = this.target;");
p.plnI("if (target == null) {");
p.pln("throw new java.io.IOException();");
p.pOln("}");
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 (String[]) _type_ids.clone();");
p.pOln("}");
} else {
p.plnI("public String[] _ids() { ");
p.pln("return (String[]) _type_ids.clone();");
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();
}
}