use of sun.tools.java.ClassDeclaration in project jdk8u_jdk by JetBrains.
the class RMIGenerator method writeStubMethod.
/**
* Write the stub method for the remote method with the given "opnum".
*/
private void writeStubMethod(IndentingWriter p, int opnum) throws IOException {
RemoteClass.Method method = remoteMethods[opnum];
Identifier methodName = method.getName();
Type methodType = method.getType();
Type[] paramTypes = methodType.getArgumentTypes();
String[] paramNames = nameParameters(paramTypes);
Type returnType = methodType.getReturnType();
ClassDeclaration[] exceptions = method.getExceptions();
/*
* Declare stub method; throw exceptions declared in remote
* interface(s).
*/
p.pln("// implementation of " + methodType.typeString(methodName.toString(), true, false));
p.p("public " + returnType + " " + methodName + "(");
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0)
p.p(", ");
p.p(paramTypes[i] + " " + paramNames[i]);
}
p.plnI(")");
if (exceptions.length > 0) {
p.p("throws ");
for (int i = 0; i < exceptions.length; i++) {
if (i > 0)
p.p(", ");
p.p(exceptions[i].getName().toString());
}
p.pln();
}
p.pOlnI("{");
/*
* The RemoteRef.invoke methods throw Exception, but unless this
* stub method throws Exception as well, we must catch Exceptions
* thrown from the invocation. So we must catch Exception and
* rethrow something we can throw: UnexpectedException, which is a
* subclass of RemoteException. But for any subclasses of Exception
* that we can throw, like RemoteException, RuntimeException, and
* any of the exceptions declared by this stub method, we want them
* to pass through unharmed, so first we must catch any such
* exceptions and rethrow it directly.
*
* We have to be careful generating the rethrowing catch blocks
* here, because javac will flag an error if there are any
* unreachable catch blocks, i.e. if the catch of an exception class
* follows a previous catch of it or of one of its superclasses.
* The following method invocation takes care of these details.
*/
Vector<ClassDefinition> catchList = computeUniqueCatchList(exceptions);
/*
* If we need to catch any particular exceptions (i.e. this method
* does not declare java.lang.Exception), put the entire stub
* method in a try block.
*/
if (catchList.size() > 0) {
p.plnI("try {");
}
if (version == STUB_VERSION_FAT) {
p.plnI("if (useNewInvoke) {");
}
if (version == STUB_VERSION_FAT || version == STUB_VERSION_1_2) {
if (!returnType.isType(TC_VOID)) {
// REMIND: why $?
p.p("Object $result = ");
}
p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
if (paramTypes.length > 0) {
p.p("new java.lang.Object[] {");
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0)
p.p(", ");
p.p(wrapArgumentCode(paramTypes[i], paramNames[i]));
}
p.p("}");
} else {
p.p("null");
}
p.pln(", " + method.getMethodHash() + "L);");
if (!returnType.isType(TC_VOID)) {
p.pln("return " + unwrapArgumentCode(returnType, "$result") + ";");
}
}
if (version == STUB_VERSION_FAT) {
p.pOlnI("} else {");
}
if (version == STUB_VERSION_1_1 || version == STUB_VERSION_FAT) {
p.pln(idRemoteCall + " call = ref.newCall((" + idRemoteObject + ") this, operations, " + opnum + ", interfaceHash);");
if (paramTypes.length > 0) {
p.plnI("try {");
p.pln("java.io.ObjectOutput out = call.getOutputStream();");
writeMarshalArguments(p, "out", paramTypes, paramNames);
p.pOlnI("} catch (java.io.IOException e) {");
p.pln("throw new " + idMarshalException + "(\"error marshalling arguments\", e);");
p.pOln("}");
}
p.pln("ref.invoke(call);");
if (returnType.isType(TC_VOID)) {
p.pln("ref.done(call);");
} else {
// REMIND: why $?
p.pln(returnType + " $result;");
p.plnI("try {");
p.pln("java.io.ObjectInput in = call.getInputStream();");
boolean objectRead = writeUnmarshalArgument(p, "in", returnType, "$result");
p.pln(";");
p.pOlnI("} catch (java.io.IOException e) {");
p.pln("throw new " + idUnmarshalException + "(\"error unmarshalling return\", e);");
/*
* If any only if readObject has been invoked, we must catch
* ClassNotFoundException as well as IOException.
*/
if (objectRead) {
p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
p.pln("throw new " + idUnmarshalException + "(\"error unmarshalling return\", e);");
}
p.pOlnI("} finally {");
p.pln("ref.done(call);");
p.pOln("}");
p.pln("return $result;");
}
}
if (version == STUB_VERSION_FAT) {
// end if/else (useNewInvoke) block
p.pOln("}");
}
/*
* If we need to catch any particular exceptions, finally write
* the catch blocks for them, rethrow any other Exceptions with an
* UnexpectedException, and end the try block.
*/
if (catchList.size() > 0) {
for (Enumeration<ClassDefinition> enumeration = catchList.elements(); enumeration.hasMoreElements(); ) {
ClassDefinition def = enumeration.nextElement();
p.pOlnI("} catch (" + def.getName() + " e) {");
p.pln("throw e;");
}
p.pOlnI("} catch (java.lang.Exception e) {");
p.pln("throw new " + idUnexpectedException + "(\"undeclared checked exception\", e);");
// end try/catch block
p.pOln("}");
}
// end stub method
p.pOln("}");
}
use of sun.tools.java.ClassDeclaration in project jdk8u_jdk by JetBrains.
the class RemoteClass method initialize.
/**
* Validate that the remote implementation class is properly formed
* and fill in the data structures required by the public interface.
*/
private boolean initialize() {
/*
* Verify that the "impl" is really a class, not an interface.
*/
if (implClassDef.isInterface()) {
env.error(0, "rmic.cant.make.stubs.for.interface", implClassDef.getName());
return false;
}
/*
* Initialize cached definitions for the Remote interface and
* the RemoteException class.
*/
try {
defRemote = env.getClassDeclaration(idRemote).getClassDefinition(env);
defException = env.getClassDeclaration(idJavaLangException).getClassDefinition(env);
defRemoteException = env.getClassDeclaration(idRemoteException).getClassDefinition(env);
} catch (ClassNotFound e) {
env.error(0, "rmic.class.not.found", e.name);
return false;
}
/*
* Here we find all of the remote interfaces of our remote
* implementation class. For each class up the superclass
* chain, add each directly-implemented interface that
* somehow extends Remote to a list.
*/
// list of remote interfaces found
Vector<ClassDefinition> remotesImplemented = new Vector<ClassDefinition>();
for (ClassDefinition classDef = implClassDef; classDef != null; ) {
try {
ClassDeclaration[] interfaces = classDef.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
ClassDefinition interfaceDef = interfaces[i].getClassDefinition(env);
/*
* Add interface to the list if it extends Remote and
* it is not already there.
*/
if (!remotesImplemented.contains(interfaceDef) && defRemote.implementedBy(env, interfaces[i])) {
remotesImplemented.addElement(interfaceDef);
/***** <DEBUG> */
if (env.verbose()) {
System.out.println("[found remote interface: " + interfaceDef.getName() + "]");
/***** </DEBUG> */
}
}
}
/*
* Verify that the candidate remote implementation class
* implements at least one remote interface directly.
*/
if (classDef == implClassDef && remotesImplemented.isEmpty()) {
if (defRemote.implementedBy(env, implClassDef.getClassDeclaration())) {
/*
* This error message is used if the class does
* implement a remote interface through one of
* its superclasses, but not directly.
*/
env.error(0, "rmic.must.implement.remote.directly", implClassDef.getName());
} else {
/*
* This error message is used if the class never
* implements a remote interface.
*/
env.error(0, "rmic.must.implement.remote", implClassDef.getName());
}
return false;
}
/*
* Get definition for next superclass.
*/
classDef = (classDef.getSuperClass() != null ? classDef.getSuperClass().getClassDefinition(env) : null);
} catch (ClassNotFound e) {
env.error(0, "class.not.found", e.name, classDef.getName());
return false;
}
}
/*
* The "remotesImplemented" vector now contains all of the remote
* interfaces directly implemented by the remote class or by any
* of its superclasses.
*
* At this point, we could optimize the list by removing superfluous
* entries, i.e. any interfaces that are implemented by some other
* interface in the list anyway.
*
* This should be correct; would it be worthwhile?
*
* for (int i = 0; i < remotesImplemented.size();) {
* ClassDefinition interfaceDef =
* (ClassDefinition) remotesImplemented.elementAt(i);
* boolean isOtherwiseImplemented = false;
* for (int j = 0; j < remotesImplemented.size; j++) {
* if (j != i &&
* interfaceDef.implementedBy(env, (ClassDefinition)
* remotesImplemented.elementAt(j).
* getClassDeclaration()))
* {
* isOtherwiseImplemented = true;
* break;
* }
* }
* if (isOtherwiseImplemented) {
* remotesImplemented.removeElementAt(i);
* } else {
* ++i;
* }
* }
*/
/*
* Now we collect the methods from all of the remote interfaces
* into a hashtable.
*/
Hashtable<String, Method> methods = new Hashtable<String, Method>();
boolean errors = false;
for (Enumeration<ClassDefinition> enumeration = remotesImplemented.elements(); enumeration.hasMoreElements(); ) {
ClassDefinition interfaceDef = enumeration.nextElement();
if (!collectRemoteMethods(interfaceDef, methods))
errors = true;
}
if (errors)
return false;
/*
* Convert vector of remote interfaces to an array
* (order is not important for this array).
*/
remoteInterfaces = new ClassDefinition[remotesImplemented.size()];
remotesImplemented.copyInto(remoteInterfaces);
/*
* Sort table of remote methods into an array. The elements are
* sorted in ascending order of the string of the method's name
* and type signature, so that each elements index is equal to
* its operation number of the JDK 1.1 version of the stub/skeleton
* protocol.
*/
String[] orderedKeys = new String[methods.size()];
int count = 0;
for (Enumeration<Method> enumeration = methods.elements(); enumeration.hasMoreElements(); ) {
Method m = enumeration.nextElement();
String key = m.getNameAndDescriptor();
int i;
for (i = count; i > 0; --i) {
if (key.compareTo(orderedKeys[i - 1]) >= 0) {
break;
}
orderedKeys[i] = orderedKeys[i - 1];
}
orderedKeys[i] = key;
++count;
}
remoteMethods = new Method[methods.size()];
for (int i = 0; i < remoteMethods.length; i++) {
remoteMethods[i] = methods.get(orderedKeys[i]);
/***** <DEBUG> */
if (env.verbose()) {
System.out.print("[found remote method <" + i + ">: " + remoteMethods[i].getOperationString());
ClassDeclaration[] exceptions = remoteMethods[i].getExceptions();
if (exceptions.length > 0)
System.out.print(" throws ");
for (int j = 0; j < exceptions.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(exceptions[j].getName());
}
System.out.println("]");
}
/***** </DEBUG> */
}
/**
* Finally, pre-compute the interface hash to be used by
* stubs/skeletons for this remote class.
*/
interfaceHash = computeInterfaceHash();
return true;
}
use of sun.tools.java.ClassDeclaration in project jdk8u_jdk by JetBrains.
the class Main method doCompile.
/**
* Do the compile with the switches and files already supplied
*/
public boolean doCompile() {
// Create batch environment
BatchEnvironment env = getEnv();
env.flags |= flags;
// Set the classfile version numbers
// Compat and 1.1 stubs must retain the old version number.
env.majorVersion = 45;
env.minorVersion = 3;
// Preload the "out of memory" error string just in case we run
// out of memory during the compile.
String noMemoryErrorString = getText("rmic.no.memory");
String stackOverflowErrorString = getText("rmic.stack.overflow");
try {
/** Load the classes on the command line
* Replace the entries in classes with the ClassDefinition for the class
*/
for (int i = classes.size() - 1; i >= 0; i--) {
Identifier implClassName = Identifier.lookup(classes.elementAt(i));
/*
* Fix bugid 4049354: support using '.' as an inner class
* qualifier on the command line (previously, only mangled
* inner class names were understood, like "pkg.Outer$Inner").
*
* The following method, also used by "javap", resolves the
* given unmangled inner class name to the appropriate
* internal identifier. For example, it translates
* "pkg.Outer.Inner" to "pkg.Outer. Inner".
*/
implClassName = env.resolvePackageQualifiedName(implClassName);
/*
* But if we use such an internal inner class name identifier
* to load the class definition, the Java compiler will notice
* if the impl class is a "private" inner class and then deny
* skeletons (needed unless "-v1.2" is used) the ability to
* cast to it. To work around this problem, we mangle inner
* class name identifiers to their binary "outer" class name:
* "pkg.Outer. Inner" becomes "pkg.Outer$Inner".
*/
implClassName = Names.mangleClass(implClassName);
ClassDeclaration decl = env.getClassDeclaration(implClassName);
try {
ClassDefinition def = decl.getClassDefinition(env);
for (int j = 0; j < generators.size(); j++) {
Generator gen = generators.elementAt(j);
gen.generate(env, def, destDir);
}
} catch (ClassNotFound ex) {
env.error(0, "rmic.class.not.found", implClassName);
}
}
// compile all classes that need compilation
if (!nocompile) {
compileAllClasses(env);
}
} catch (OutOfMemoryError ee) {
// The compiler has run out of memory. Use the error string
// which we preloaded.
env.output(noMemoryErrorString);
return false;
} catch (StackOverflowError ee) {
env.output(stackOverflowErrorString);
return false;
} catch (Error ee) {
// compiler more robust in the face of bad error recovery.
if (env.nerrors == 0 || env.dump()) {
env.error(0, "fatal.error");
ee.printStackTrace(out instanceof PrintStream ? (PrintStream) out : new PrintStream(out, true));
}
} catch (Exception ee) {
if (env.nerrors == 0 || env.dump()) {
env.error(0, "fatal.exception");
ee.printStackTrace(out instanceof PrintStream ? (PrintStream) out : new PrintStream(out, true));
}
}
env.flushErrors();
boolean status = true;
if (env.nerrors > 0) {
String msg = "";
if (env.nerrors > 1) {
msg = getText("rmic.errors", env.nerrors);
} else {
msg = getText("rmic.1error");
}
if (env.nwarnings > 0) {
if (env.nwarnings > 1) {
msg += ", " + getText("rmic.warnings", env.nwarnings);
} else {
msg += ", " + getText("rmic.1warning");
}
}
output(msg);
status = false;
} else {
if (env.nwarnings > 0) {
if (env.nwarnings > 1) {
output(getText("rmic.warnings", env.nwarnings));
} else {
output(getText("rmic.1warning"));
}
}
}
// last step is to delete generated source files
if (!keepGenerated) {
env.deleteGeneratedFiles();
}
// We're done
if (env.verbose()) {
tm = System.currentTimeMillis() - tm;
output(getText("rmic.done_in", Long.toString(tm)));
}
// Shutdown the environment object and release our resources.
// Note that while this is unneccessary when rmic is invoked
// the command line, there are environments in which rmic
// from is invoked within a server process, so resource
// reclamation is important...
env.shutdown();
sourcePathArg = null;
sysClassPathArg = null;
extDirsArg = null;
classPathString = null;
destDir = null;
classes = null;
generatorArgs = null;
generators = null;
environmentClass = null;
program = null;
out = null;
return status;
}
use of sun.tools.java.ClassDeclaration in project jdk8u_jdk by JetBrains.
the class RemoteClass method sortClassDeclarations.
/**
* Sort array of class declarations alphabetically by their mangled
* fully-qualified class name. This is used to feed a method's exceptions
* in a canonical order into the digest stream for the interface hash
* computation.
*/
private void sortClassDeclarations(ClassDeclaration[] decl) {
for (int i = 1; i < decl.length; i++) {
ClassDeclaration curr = decl[i];
String name = Names.mangleClass(curr.getName()).toString();
int j;
for (j = i; j > 0; j--) {
if (name.compareTo(Names.mangleClass(decl[j - 1].getName()).toString()) >= 0) {
break;
}
decl[j] = decl[j - 1];
}
decl[j] = curr;
}
}
use of sun.tools.java.ClassDeclaration in project jdk8u_jdk by JetBrains.
the class RemoteClass method computeInterfaceHash.
/**
* Compute the "interface hash" of the stub/skeleton pair for this
* remote implementation class. This is the 64-bit value used to
* enforce compatibility between a stub and a skeleton using the
* JDK 1.1 version of the stub/skeleton protocol.
*
* It is calculated using the first 64 bits of a SHA digest. The
* digest is from a stream consisting of the following data:
* (int) stub version number, always 1
* for each remote method, in order of operation number:
* (UTF) method name
* (UTF) method type signature
* for each declared exception, in alphabetical name order:
* (UTF) name of exception class
*
*/
private long computeInterfaceHash() {
long hash = 0;
ByteArrayOutputStream sink = new ByteArrayOutputStream(512);
try {
MessageDigest md = MessageDigest.getInstance("SHA");
DataOutputStream out = new DataOutputStream(new DigestOutputStream(sink, md));
out.writeInt(INTERFACE_HASH_STUB_VERSION);
for (int i = 0; i < remoteMethods.length; i++) {
MemberDefinition m = remoteMethods[i].getMemberDefinition();
Identifier name = m.getName();
Type type = m.getType();
out.writeUTF(name.toString());
// type signatures already use mangled class names
out.writeUTF(type.getTypeSignature());
ClassDeclaration[] exceptions = m.getExceptions(env);
sortClassDeclarations(exceptions);
for (int j = 0; j < exceptions.length; j++) {
out.writeUTF(Names.mangleClass(exceptions[j].getName()).toString());
}
}
out.flush();
// use only the first 64 bits of the digest for the hash
byte[] hashArray = md.digest();
for (int i = 0; i < Math.min(8, hashArray.length); i++) {
hash += ((long) (hashArray[i] & 0xFF)) << (i * 8);
}
} catch (IOException e) {
throw new Error("unexpected exception computing intetrface hash: " + e);
} catch (NoSuchAlgorithmException e) {
throw new Error("unexpected exception computing intetrface hash: " + e);
}
return hash;
}
Aggregations