Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ow2.fastrmic.RMIC Maven / Gradle / Ivy
/**
RMIC.java --
Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath 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 for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
package org.ow2.fastrmic;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.MarshalException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.UnexpectedException;
import java.rmi.UnmarshalException;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
import java.rmi.server.RemoteStub;
import java.rmi.server.Skeleton;
import java.rmi.server.SkeletonMismatchException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class RMIC implements Opcodes {
private String[] args;
private int next;
private Exception exception;
private boolean keep = false;
private boolean need11Stubs = true;
private boolean need12Stubs = true;
private boolean compile = true;
private boolean verbose;
private String destination;
private String classpath;
private ClassLoader loader;
private int errorCount = 0;
private Class clazz;
private String classname;
private String classInternalName;
private String fullclassname;
private MethodRef[] remotemethods;
private String stubname;
private String skelname;
private List mRemoteInterfaces;
/**
* System property used to let ASM compute the max var.
*/
private static final String COMPUTE_MAX = "fastrmic.asm.computemax";
public RMIC(String[] a) {
args = a;
}
public static void main(String[] args) {
RMIC r = new RMIC(args);
if (r.run() == false) {
Exception e = r.getException();
if (e != null)
e.printStackTrace();
else
System.exit(1);
}
}
public boolean run() {
parseOptions();
if (next >= args.length)
error("no class names found");
for (int i = next; i < args.length; i++) {
try {
if (verbose)
System.out.println("[Processing class " + args[i]
+ ".class]");
processClass(args[i].replace(File.separatorChar, '.'));
} catch (Exception e) {
exception = e;
return (false);
}
}
return (true);
}
private boolean processClass(String cls) throws Exception {
// reset class specific vars
clazz = null;
classname = null;
classInternalName = null;
fullclassname = null;
remotemethods = null;
stubname = null;
skelname = null;
mRemoteInterfaces = new ArrayList();
errorCount = 0;
analyzeClass(cls);
if (errorCount > 0)
System.exit(1);
generateStub();
if (need11Stubs)
generateSkel();
return (true);
}
private void analyzeClass(String cname) throws Exception {
if (verbose)
System.out.println("[analyze class " + cname + "]");
int p = cname.lastIndexOf('.');
if (p != -1)
classname = cname.substring(p + 1);
else
classname = cname;
fullclassname = cname;
findClass();
findRemoteMethods();
}
public Exception getException() {
return (exception);
}
private void findClass() {
try {
ClassLoader cl = (loader == null ? ClassLoader
.getSystemClassLoader() : loader);
clazz = Class.forName(fullclassname, false, cl);
} catch (ClassNotFoundException cnfe) {
System.err.println(fullclassname + " not found in " + classpath);
throw new RuntimeException(cnfe);
}
if (!Remote.class.isAssignableFrom(clazz)) {
logError("Class " + clazz.getName() + " is not a remote object. "
+ "It does not implement an interface that is a "
+ "java.rmi.Remote-interface.");
throw new RuntimeException("Class " + clazz.getName()
+ " is not a remote object. "
+ "It does not implement an interface that is a "
+ "java.rmi.Remote-interface.");
}
}
private static Type[] typeArray(Class[] cls) {
Type[] t = new Type[cls.length];
for (int i = 0; i < cls.length; i++) {
t[i] = Type.getType(cls[i]);
}
return t;
}
private static String[] internalNameArray(Type[] t) {
String[] s = new String[t.length];
for (int i = 0; i < t.length; i++) {
s[i] = t[i].getInternalName();
}
return s;
}
private static String[] internalNameArray(Class[] c) {
return internalNameArray(typeArray(c));
}
private static final String forName = "class$";
private static Object param(Method m, int argIndex) {
List l = new ArrayList();
l.add(m);
l.add(new Integer(argIndex));
return l;
}
private static void generateClassForNamer(ClassVisitor cls) {
MethodVisitor cv = cls.visitMethod(ACC_PRIVATE + ACC_STATIC
+ ACC_SYNTHETIC, forName, Type.getMethodDescriptor(Type
.getType(Class.class),
new Type[] { Type.getType(String.class) }), null, null);
Label start = new Label();
cv.visitLabel(start);
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Class.class),
"forName", Type.getMethodDescriptor(Type.getType(Class.class),
new Type[] { Type.getType(String.class) }));
cv.visitInsn(ARETURN);
Label handler = new Label();
cv.visitLabel(handler);
cv.visitVarInsn(ASTORE, 1);
cv.visitTypeInsn(NEW, typeArg(NoClassDefFoundError.class));
cv.visitInsn(DUP);
cv.visitVarInsn(ALOAD, 1);
cv.visitMethodInsn(INVOKEVIRTUAL, Type
.getInternalName(ClassNotFoundException.class), "getMessage",
Type.getMethodDescriptor(Type.getType(String.class),
new Type[] {}));
cv.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(NoClassDefFoundError.class), "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(String.class) }));
cv.visitInsn(ATHROW);
cv.visitTryCatchBlock(start, handler, handler, Type
.getInternalName(ClassNotFoundException.class));
cv.visitMaxs(-1, -1);
}
private void generateClassConstant(MethodVisitor cv, Class cls) {
if (cls.isPrimitive()) {
Class boxCls;
if (cls.equals(Boolean.TYPE))
boxCls = Boolean.class;
else if (cls.equals(Character.TYPE))
boxCls = Character.class;
else if (cls.equals(Byte.TYPE))
boxCls = Byte.class;
else if (cls.equals(Short.TYPE))
boxCls = Short.class;
else if (cls.equals(Integer.TYPE))
boxCls = Integer.class;
else if (cls.equals(Long.TYPE))
boxCls = Long.class;
else if (cls.equals(Float.TYPE))
boxCls = Float.class;
else if (cls.equals(Double.TYPE))
boxCls = Double.class;
else if (cls.equals(Void.TYPE))
boxCls = Void.class;
else
throw new IllegalArgumentException("unknown primitive type "
+ cls);
cv.visitFieldInsn(GETSTATIC, Type.getInternalName(boxCls), "TYPE",
Type.getDescriptor(Class.class));
return;
}
cv.visitLdcInsn(cls.getName());
cv.visitMethodInsn(INVOKESTATIC, classInternalName, forName, Type
.getMethodDescriptor(Type.getType(Class.class),
new Type[] { Type.getType(String.class) }));
}
private void generateClassArray(MethodVisitor code, Class[] classes) {
code.visitLdcInsn(new Integer(classes.length));
code.visitTypeInsn(ANEWARRAY, typeArg(Class.class));
for (int i = 0; i < classes.length; i++) {
code.visitInsn(DUP);
code.visitLdcInsn(new Integer(i));
generateClassConstant(code, classes[i]);
code.visitInsn(AASTORE);
}
}
private void fillOperationArray(MethodVisitor clinit) {
// Operations array
clinit.visitLdcInsn(new Integer(remotemethods.length));
clinit.visitTypeInsn(ANEWARRAY, typeArg(Operation.class));
clinit.visitFieldInsn(PUTSTATIC, classInternalName, "operations", Type
.getDescriptor(Operation[].class));
for (int i = 0; i < remotemethods.length; i++) {
Method m = remotemethods[i].meth;
StringBuffer desc = new StringBuffer();
desc.append(getPrettyName(m.getReturnType()) + " ");
desc.append(m.getName() + "(");
// signature
Class[] sig = m.getParameterTypes();
for (int j = 0; j < sig.length; j++) {
desc.append(getPrettyName(sig[j]));
if (j + 1 < sig.length)
desc.append(", ");
}
desc.append(")");
// push operations array
clinit.visitFieldInsn(GETSTATIC, classInternalName, "operations",
Type.getDescriptor(Operation[].class));
// push array index
clinit.visitLdcInsn(new Integer(i));
// instantiate operation and leave a copy on the stack
clinit.visitTypeInsn(NEW, typeArg(Operation.class));
clinit.visitInsn(DUP);
clinit.visitLdcInsn(desc.toString());
clinit.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(Operation.class), "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(String.class) }));
// store in operations array
clinit.visitInsn(AASTORE);
}
}
private void generateStaticMethodObjs(MethodVisitor clinit) {
for (int i = 0; i < remotemethods.length; i++) {
Method m = remotemethods[i].meth;
/*
* $method_m.getName() _i =
* m.getDeclaringClass() .class.getMethod (m.getName(),
* m.getParameterType())
*/
String methodVar = "$method_" + m.getName() + "_" + i;
generateClassConstant(clinit, m.getDeclaringClass());
clinit.visitLdcInsn(m.getName());
generateClassArray(clinit, m.getParameterTypes());
clinit.visitMethodInsn(INVOKEVIRTUAL, Type
.getInternalName(Class.class), "getMethod", Type
.getMethodDescriptor(Type.getType(Method.class),
new Type[] { Type.getType(String.class),
Type.getType(Class[].class) }));
clinit.visitFieldInsn(PUTSTATIC, classInternalName, methodVar, Type
.getDescriptor(Method.class));
}
}
private void generateStub() throws IOException {
ClassInfo classInfo = generateStubData();
File file = new File((destination == null ? "." : destination)
+ File.separator
+ classInfo.getName().replace('.', File.separatorChar)
+ ".class");
if (file.exists())
file.delete();
if (file.getParentFile() != null)
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
fos.write(classInfo.getBytecode());
fos.flush();
fos.close();
}
private ClassInfo generateStubData() throws IOException {
ClassInfo classInfo = new ClassInfo();
stubname = fullclassname + "_Stub";
classInfo.setName(stubname);
if (verbose)
System.out.println("[Generating class " + stubname + "]");
final ClassWriter stub = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classInternalName = stubname.replace('.', '/');
final String superInternalName = Type.getType(RemoteStub.class)
.getInternalName();
String[] remoteInternalNames = internalNameArray((Class[]) mRemoteInterfaces
.toArray(new Class[] {}));
stub.visit(V1_2, ACC_PUBLIC + ACC_FINAL, classInternalName, null,
superInternalName, remoteInternalNames);
if (need12Stubs) {
stub.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL,
"serialVersionUID", Type.LONG_TYPE.getDescriptor(), null,
new Long(2L));
}
if (need11Stubs) {
stub.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL,
"interfaceHash", Type.LONG_TYPE.getDescriptor(), null,
new Long(getInterfaceHash(clazz)));
if (need12Stubs) {
stub.visitField(ACC_PRIVATE + ACC_STATIC, "useNewInvoke",
Type.BOOLEAN_TYPE.getDescriptor(), null, null);
}
stub.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL, "operations",
Type.getDescriptor(Operation[].class), null, null);
}
// Set of method references.
if (need12Stubs) {
for (int i = 0; i < remotemethods.length; i++) {
Method m = remotemethods[i].meth;
String slotName = "$method_" + m.getName() + "_" + i;
stub.visitField(ACC_PRIVATE + ACC_STATIC, slotName, Type
.getDescriptor(Method.class), null, null);
}
}
MethodVisitor clinit = stub
.visitMethod(ACC_STATIC, "", Type.getMethodDescriptor(
Type.VOID_TYPE, new Type[] {}), null, null);
if (need11Stubs) {
fillOperationArray(clinit);
if (!need12Stubs)
clinit.visitInsn(RETURN);
}
if (need12Stubs) {
// begin of try
Label begin = new Label();
// beginning of catch
Label handler = new Label();
clinit.visitLabel(begin);
// Initialize the methods references.
if (need11Stubs) {
/*
* RemoteRef.class.getMethod("invoke", new Class[] {
* Remote.class, Method.class, Object[].class, long.class })
*/
generateClassConstant(clinit, RemoteRef.class);
clinit.visitLdcInsn("invoke");
generateClassArray(clinit, new Class[] { Remote.class,
Method.class, Object[].class, long.class });
clinit.visitMethodInsn(INVOKEVIRTUAL, Type
.getInternalName(Class.class), "getMethod", Type
.getMethodDescriptor(Type.getType(Method.class),
new Type[] { Type.getType(String.class),
Type.getType(Class[].class) }));
// useNewInvoke = true
clinit.visitInsn(ICONST_1);
clinit.visitFieldInsn(PUTSTATIC, classInternalName,
"useNewInvoke", Type.BOOLEAN_TYPE.getDescriptor());
}
generateStaticMethodObjs(clinit);
// jump past handler
clinit.visitInsn(RETURN);
clinit.visitLabel(handler);
if (need11Stubs) {
// useNewInvoke = false
clinit.visitInsn(ICONST_0);
clinit.visitFieldInsn(PUTSTATIC, classInternalName,
"useNewInvoke", Type.BOOLEAN_TYPE.getDescriptor());
clinit.visitInsn(RETURN);
} else {
// throw NoSuchMethodError
clinit.visitTypeInsn(NEW, typeArg(NoSuchMethodError.class));
clinit.visitInsn(DUP);
clinit.visitLdcInsn("stub class initialization failed");
clinit.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(NoSuchMethodError.class), "",
Type.getMethodDescriptor(Type.VOID_TYPE,
new Type[] { Type.getType(String.class) }));
clinit.visitInsn(ATHROW);
}
clinit.visitTryCatchBlock(begin, handler, handler, Type
.getInternalName(NoSuchMethodException.class));
}
clinit.visitMaxs(-1, -1);
generateClassForNamer(stub);
// Constructors
if (need11Stubs) {
// no arg public constructor
MethodVisitor code = stub.visitMethod(ACC_PUBLIC, "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null,
null);
code.visitVarInsn(ALOAD, 0);
code.visitMethodInsn(INVOKESPECIAL, superInternalName, "",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
code.visitInsn(RETURN);
code.visitMaxs(-1, -1);
}
// public RemoteRef constructor
MethodVisitor constructor = stub.visitMethod(ACC_PUBLIC, "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(RemoteRef.class) }), null, null);
constructor.visitVarInsn(ALOAD, 0);
constructor.visitVarInsn(ALOAD, 1);
constructor.visitMethodInsn(INVOKESPECIAL, superInternalName, "",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(RemoteRef.class) }));
constructor.visitInsn(RETURN);
constructor.visitMaxs(-1, -1);
// Method implementations
for (int i = 0; i < remotemethods.length; i++) {
Method m = remotemethods[i].meth;
Class[] sig = m.getParameterTypes();
Class returntype = m.getReturnType();
Class[] except = sortExceptions((Class[]) remotemethods[i].exceptions
.toArray(new Class[0]));
MethodVisitor code = stub.visitMethod(ACC_PUBLIC, m.getName(), Type
.getMethodDescriptor(Type.getType(returntype),
typeArray(sig)), null,
internalNameArray(typeArray(except)));
final Variables var = new Variables();
// this and parameters are the declared vars
var.declare("this");
for (int j = 0; j < sig.length; j++)
var.declare(param(m, j), size(sig[j]));
Label methodTryBegin = new Label();
code.visitLabel(methodTryBegin);
if (need12Stubs) {
Label oldInvoke = new Label();
if (need11Stubs) {
// if not useNewInvoke jump to old invoke
code.visitFieldInsn(GETSTATIC, classInternalName,
"useNewInvoke", Type.getDescriptor(boolean.class));
code.visitJumpInsn(IFEQ, oldInvoke);
}
// this.ref
code.visitVarInsn(ALOAD, var.get("this"));
code.visitFieldInsn(GETFIELD, Type
.getInternalName(RemoteObject.class), "ref", Type
.getDescriptor(RemoteRef.class));
// "this" is first arg to invoke
code.visitVarInsn(ALOAD, var.get("this"));
// method object is second arg to invoke
String methName = "$method_" + m.getName() + "_" + i;
code.visitFieldInsn(GETSTATIC, classInternalName, methName,
Type.getDescriptor(Method.class));
// args to remote method are third arg to invoke
if (sig.length == 0)
code.visitInsn(ACONST_NULL);
else {
// create arg Object[] (with boxed primitives) and push it
code.visitLdcInsn(new Integer(sig.length));
code.visitTypeInsn(ANEWARRAY, typeArg(Object.class));
var.allocate("argArray");
code.visitVarInsn(ASTORE, var.get("argArray"));
for (int j = 0; j < sig.length; j++) {
int size = size(sig[j]);
int insn = loadOpcode(sig[j]);
Class box = sig[j].isPrimitive() ? box(sig[j]) : null;
code.visitVarInsn(ALOAD, var.get("argArray"));
code.visitLdcInsn(new Integer(j));
// put argument on stack
if (box != null) {
code.visitTypeInsn(NEW, typeArg(box));
code.visitInsn(DUP);
code.visitVarInsn(insn, var.get(param(m, j)));
code
.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(box), "",
Type.getMethodDescriptor(
Type.VOID_TYPE,
new Type[] { Type
.getType(sig[j]) }));
} else
code.visitVarInsn(insn, var.get(param(m, j)));
code.visitInsn(AASTORE);
}
code.visitVarInsn(ALOAD, var.deallocate("argArray"));
}
// push remote operation opcode
code.visitLdcInsn(new Long(remotemethods[i].hash));
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteRef.class), "invoke", Type
.getMethodDescriptor(Type.getType(Object.class),
new Type[] { Type.getType(Remote.class),
Type.getType(Method.class),
Type.getType(Object[].class),
Type.LONG_TYPE }));
if (!returntype.equals(Void.TYPE)) {
int retcode = returnOpcode(returntype);
Class boxCls = returntype.isPrimitive() ? box(returntype)
: null;
code.visitTypeInsn(CHECKCAST,
typeArg(boxCls == null ? returntype : boxCls));
if (returntype.isPrimitive()) {
// unbox
code.visitMethodInsn(INVOKEVIRTUAL, Type
.getType(boxCls).getInternalName(),
unboxMethod(returntype), Type
.getMethodDescriptor(Type
.getType(returntype),
new Type[] {}));
}
code.visitInsn(retcode);
} else
code.visitInsn(RETURN);
if (need11Stubs)
code.visitLabel(oldInvoke);
}
if (need11Stubs) {
// this.ref.newCall(this, operations, index, interfaceHash)
code.visitVarInsn(ALOAD, var.get("this"));
code.visitFieldInsn(GETFIELD, Type
.getInternalName(RemoteObject.class), "ref", Type
.getDescriptor(RemoteRef.class));
// "this" is first arg to newCall
code.visitVarInsn(ALOAD, var.get("this"));
// operations is second arg to newCall
code.visitFieldInsn(GETSTATIC, classInternalName, "operations",
Type.getDescriptor(Operation[].class));
// method index is third arg
code.visitLdcInsn(new Integer(i));
// interface hash is fourth arg
code.visitFieldInsn(GETSTATIC, classInternalName,
"interfaceHash", Type.LONG_TYPE.getDescriptor());
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteRef.class), "newCall", Type
.getMethodDescriptor(Type.getType(RemoteCall.class),
new Type[] { Type.getType(RemoteObject.class),
Type.getType(Operation[].class),
Type.INT_TYPE, Type.LONG_TYPE }));
// store call object on stack and leave copy on stack
var.allocate("call");
code.visitInsn(DUP);
code.visitVarInsn(ASTORE, var.get("call"));
Label beginArgumentTryBlock = new Label();
code.visitLabel(beginArgumentTryBlock);
// ObjectOutput out = call.getOutputStream();
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteCall.class), "getOutputStream",
Type.getMethodDescriptor(Type
.getType(ObjectOutput.class), new Type[] {}));
for (int j = 0; j < sig.length; j++) {
// dup the ObjectOutput
code.visitInsn(DUP);
// get j'th arg to remote method
code.visitVarInsn(loadOpcode(sig[j]), var.get(param(m, j)));
Class argCls = sig[j].isPrimitive() ? sig[j] : Object.class;
// out.writeFoo
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(ObjectOutput.class),
writeMethod(sig[j]), Type.getMethodDescriptor(
Type.VOID_TYPE, new Type[] { Type
.getType(argCls) }));
}
// pop ObjectOutput
code.visitInsn(POP);
Label iohandler = new Label();
Label endArgumentTryBlock = new Label();
code.visitJumpInsn(GOTO, endArgumentTryBlock);
code.visitLabel(iohandler);
// throw new MarshalException(msg, ioexception);
code.visitVarInsn(ASTORE, var.allocate("exception"));
code.visitTypeInsn(NEW, typeArg(MarshalException.class));
code.visitInsn(DUP);
code.visitLdcInsn("error marshalling arguments");
code.visitVarInsn(ALOAD, var.deallocate("exception"));
code.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(MarshalException.class), "",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(String.class),
Type.getType(Exception.class) }));
code.visitInsn(ATHROW);
code.visitLabel(endArgumentTryBlock);
code.visitTryCatchBlock(beginArgumentTryBlock, iohandler,
iohandler, Type.getInternalName(IOException.class));
// this.ref.invoke(call)
code.visitVarInsn(ALOAD, var.get("this"));
code.visitFieldInsn(GETFIELD, Type
.getInternalName(RemoteObject.class), "ref", Type
.getDescriptor(RemoteRef.class));
code.visitVarInsn(ALOAD, var.get("call"));
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteRef.class), "invoke", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(RemoteCall.class) }));
// handle return value
boolean needcastcheck = false;
Label beginReturnTryCatch = new Label();
code.visitLabel(beginReturnTryCatch);
int returncode = returnOpcode(returntype);
if (!returntype.equals(Void.TYPE)) {
// call.getInputStream()
code.visitVarInsn(ALOAD, var.get("call"));
code
.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteCall.class),
"getInputStream", Type.getMethodDescriptor(
Type.getType(ObjectInput.class),
new Type[] {}));
Class readCls = returntype.isPrimitive() ? returntype
: Object.class;
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(ObjectInput.class),
readMethod(returntype), Type.getMethodDescriptor(
Type.getType(readCls), new Type[] {}));
boolean castresult = false;
if (!returntype.isPrimitive()) {
if (!returntype.equals(Object.class))
castresult = true;
else
needcastcheck = true;
}
if (castresult)
code.visitTypeInsn(CHECKCAST, typeArg(returntype));
// leave result on stack for return
}
// this.ref.done(call)
code.visitVarInsn(ALOAD, var.get("this"));
code.visitFieldInsn(GETFIELD, Type
.getInternalName(RemoteObject.class), "ref", Type
.getDescriptor(RemoteRef.class));
code.visitVarInsn(ALOAD, var.deallocate("call"));
code.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteRef.class), "done", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(RemoteCall.class) }));
// return; or return result;
code.visitInsn(returncode);
// exception handler
Label handler = new Label();
code.visitLabel(handler);
code.visitVarInsn(ASTORE, var.allocate("exception"));
// throw new UnmarshalException(msg, e)
code.visitTypeInsn(NEW, typeArg(UnmarshalException.class));
code.visitInsn(DUP);
code.visitLdcInsn("error unmarshalling return");
code.visitVarInsn(ALOAD, var.deallocate("exception"));
code.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(UnmarshalException.class), "",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(String.class),
Type.getType(Exception.class) }));
code.visitInsn(ATHROW);
Label endReturnTryCatch = new Label();
// catch IOException
code.visitTryCatchBlock(beginReturnTryCatch, handler, handler,
Type.getInternalName(IOException.class));
if (needcastcheck) {
// catch ClassNotFoundException
code.visitTryCatchBlock(beginReturnTryCatch, handler,
handler,
Type.getInternalName(ClassNotFoundException.class));
}
}
Label rethrowHandler = new Label();
code.visitLabel(rethrowHandler);
// rethrow declared exceptions
code.visitInsn(ATHROW);
boolean needgeneral = true;
for (int j = 0; j < except.length; j++) {
if (except[j] == Exception.class)
needgeneral = false;
}
for (int j = 0; j < except.length; j++) {
code.visitTryCatchBlock(methodTryBegin, rethrowHandler,
rethrowHandler, Type.getInternalName(except[j]));
}
if (needgeneral) {
// rethrow unchecked exceptions
code.visitTryCatchBlock(methodTryBegin, rethrowHandler,
rethrowHandler, Type
.getInternalName(RuntimeException.class));
Label generalHandler = new Label();
code.visitLabel(generalHandler);
String msg = "undeclared checked exception";
// throw new java.rmi.UnexpectedException(msg, e)
code.visitVarInsn(ASTORE, var.allocate("exception"));
code.visitTypeInsn(NEW, typeArg(UnexpectedException.class));
code.visitInsn(DUP);
code.visitLdcInsn(msg);
code.visitVarInsn(ALOAD, var.deallocate("exception"));
code.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(UnexpectedException.class), "",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(String.class),
Type.getType(Exception.class) }));
code.visitInsn(ATHROW);
code.visitTryCatchBlock(methodTryBegin, rethrowHandler,
generalHandler, Type.getInternalName(Exception.class));
}
code.visitMaxs(-1, -1);
}
stub.visitEnd();
byte[] classData = stub.toByteArray();
classInfo.setBytecode(classData);
return classInfo;
}
private void generateSkel() throws IOException {
ClassInfo classInfo = generateSkelData();
File file = new File(destination == null ? "" : destination
+ File.separator
+ classInfo.getName().replace('.', File.separatorChar)
+ ".class");
if (file.exists())
file.delete();
if (file.getParentFile() != null)
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
fos.write(classInfo.getBytecode());
fos.flush();
fos.close();
}
private ClassInfo generateSkelData() throws IOException {
ClassInfo classInfo = new ClassInfo();
skelname = fullclassname + "_Skel";
classInfo.setName(skelname);
if (verbose)
System.out.println("[Generating class " + skelname + "]");
final ClassWriter skel;
if (Boolean.getBoolean(COMPUTE_MAX)) {
// Let asm to compute the MAXs
skel = new ClassWriter(ClassWriter.COMPUTE_MAXS);
} else {
skel = new ClassWriter(0);
}
classInternalName = skelname.replace('.', '/');
skel.visit(V1_1, ACC_PUBLIC + ACC_FINAL, classInternalName, null, Type
.getInternalName(Object.class), new String[] { Type.getType(
Skeleton.class).getInternalName() });
skel.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL, "interfaceHash",
Type.LONG_TYPE.getDescriptor(), null, new Long(
getInterfaceHash(clazz)));
skel.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL, "operations",
Type.getDescriptor(Operation[].class), null, null);
MethodVisitor clinit = skel
.visitMethod(ACC_STATIC, "", Type.getMethodDescriptor(
Type.VOID_TYPE, new Type[] {}), null, null);
fillOperationArray(clinit);
clinit.visitInsn(RETURN);
clinit.visitMaxs(10, 5);
// no arg public constructor
MethodVisitor init = skel
.visitMethod(ACC_PUBLIC, "", Type.getMethodDescriptor(
Type.VOID_TYPE, new Type[] {}), null, null);
init.visitVarInsn(ALOAD, 0);
init.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class),
"", Type.getMethodDescriptor(Type.VOID_TYPE,
new Type[] {}));
init.visitInsn(RETURN);
init.visitMaxs(10, 5);
/*
* public Operation[] getOperations() returns a clone of the operations
* array
*/
MethodVisitor getOp = skel.visitMethod(ACC_PUBLIC, "getOperations",
Type.getMethodDescriptor(Type.getType(Operation[].class),
new Type[] {}), null, null);
getOp.visitFieldInsn(GETSTATIC, classInternalName, "operations", Type
.getDescriptor(Operation[].class));
getOp.visitMethodInsn(INVOKEVIRTUAL,
Type.getInternalName(Object.class), "clone", Type
.getMethodDescriptor(Type.getType(Object.class),
new Type[] {}));
getOp.visitTypeInsn(CHECKCAST, typeArg(Operation[].class));
getOp.visitInsn(ARETURN);
getOp.visitMaxs(10, 5);
// public void dispatch(Remote, RemoteCall, int opnum, long hash)
MethodVisitor dispatch = skel.visitMethod(ACC_PUBLIC, "dispatch", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(Remote.class),
Type.getType(RemoteCall.class), Type.INT_TYPE,
Type.LONG_TYPE }), null, new String[] { Type
.getInternalName(Exception.class) });
Variables var = new Variables();
var.declare("this");
var.declare("remoteobj");
var.declare("remotecall");
var.declare("opnum");
var.declareWide("hash");
/*
* if opnum >= 0 XXX it is unclear why there is handling of negative
* opnums
*/
dispatch.visitVarInsn(ILOAD, var.get("opnum"));
Label nonNegativeOpnum = new Label();
Label opnumSet = new Label();
dispatch.visitJumpInsn(IFGE, nonNegativeOpnum);
for (int i = 0; i < remotemethods.length; i++) {
// assign opnum if hash matches supplied hash
dispatch.visitVarInsn(LLOAD, var.get("hash"));
dispatch.visitLdcInsn(new Long(remotemethods[i].hash));
Label notit = new Label();
dispatch.visitInsn(LCMP);
dispatch.visitJumpInsn(IFNE, notit);
// opnum =
dispatch.visitLdcInsn(new Integer(i));
dispatch.visitVarInsn(ISTORE, var.get("opnum"));
dispatch.visitJumpInsn(GOTO, opnumSet);
dispatch.visitLabel(notit);
}
// throw new SkeletonMismatchException
Label mismatch = new Label();
dispatch.visitJumpInsn(GOTO, mismatch);
dispatch.visitLabel(nonNegativeOpnum);
// if opnum is already set, check that the hash matches the interface
dispatch.visitVarInsn(LLOAD, var.get("hash"));
dispatch.visitFieldInsn(GETSTATIC, classInternalName, "interfaceHash",
Type.LONG_TYPE.getDescriptor());
dispatch.visitInsn(LCMP);
dispatch.visitJumpInsn(IFEQ, opnumSet);
dispatch.visitLabel(mismatch);
dispatch.visitTypeInsn(NEW, typeArg(SkeletonMismatchException.class));
dispatch.visitInsn(DUP);
dispatch.visitLdcInsn("interface hash mismatch");
dispatch.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(SkeletonMismatchException.class), "",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(String.class) }));
dispatch.visitInsn(ATHROW);
// opnum has been set
dispatch.visitLabel(opnumSet);
dispatch.visitVarInsn(ALOAD, var.get("remoteobj"));
dispatch.visitTypeInsn(CHECKCAST, typeArg(clazz));
dispatch.visitVarInsn(ASTORE, var.get("remoteobj"));
Label deflt = new Label();
Label[] methLabels = new Label[remotemethods.length];
for (int i = 0; i < methLabels.length; i++)
methLabels[i] = new Label();
// switch on opnum
dispatch.visitVarInsn(ILOAD, var.get("opnum"));
dispatch.visitTableSwitchInsn(0, remotemethods.length - 1, deflt,
methLabels);
// Method dispatch
for (int i = 0; i < remotemethods.length; i++) {
dispatch.visitLabel(methLabels[i]);
Method m = remotemethods[i].meth;
generateMethodSkel(dispatch, m, var);
}
dispatch.visitLabel(deflt);
dispatch.visitTypeInsn(NEW, typeArg(UnmarshalException.class));
dispatch.visitInsn(DUP);
dispatch.visitLdcInsn("invalid method number");
dispatch.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(UnmarshalException.class), "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type
.getType(String.class) }));
dispatch.visitInsn(ATHROW);
dispatch.visitMaxs(3 * remotemethods.length, var.max() + 1);
skel.visitEnd();
byte[] classData = skel.toByteArray();
classInfo.setBytecode(classData);
return classInfo;
}
private void generateMethodSkel(MethodVisitor cv, Method m, Variables var) {
Class[] sig = m.getParameterTypes();
Label readArgs = new Label();
cv.visitLabel(readArgs);
boolean needcastcheck = false;
// ObjectInput in = call.getInputStream();
cv.visitVarInsn(ALOAD, var.get("remotecall"));
cv.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteCall.class), "getInputStream", Type
.getMethodDescriptor(Type.getType(ObjectInput.class),
new Type[] {}));
cv.visitVarInsn(ASTORE, var.allocate("objectinput"));
for (int i = 0; i < sig.length; i++) {
// dup input stream
cv.visitVarInsn(ALOAD, var.get("objectinput"));
Class readCls = sig[i].isPrimitive() ? sig[i] : Object.class;
// in.readFoo()
cv.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(ObjectInput.class), readMethod(sig[i]),
Type.getMethodDescriptor(Type.getType(readCls),
new Type[] {}));
if (!sig[i].isPrimitive() && !sig[i].equals(Object.class)) {
needcastcheck = true;
cv.visitTypeInsn(CHECKCAST, typeArg(sig[i]));
}
// store arg in variable
cv.visitVarInsn(storeOpcode(sig[i]), var.allocate(param(m, i),
size(sig[i])));
}
var.deallocate("objectinput");
Label doCall = new Label();
Label closeInput = new Label();
cv.visitJumpInsn(JSR, closeInput);
cv.visitJumpInsn(GOTO, doCall);
// throw new UnmarshalException
Label handler = new Label();
cv.visitLabel(handler);
cv.visitVarInsn(ASTORE, var.allocate("exception"));
cv.visitTypeInsn(NEW, typeArg(UnmarshalException.class));
cv.visitInsn(DUP);
cv.visitLdcInsn("error unmarshalling arguments");
cv.visitVarInsn(ALOAD, var.deallocate("exception"));
cv.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(UnmarshalException.class), "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(String.class),
Type.getType(Exception.class) }));
cv.visitVarInsn(ASTORE, var.allocate("toThrow"));
cv.visitJumpInsn(JSR, closeInput);
cv.visitVarInsn(ALOAD, var.get("toThrow"));
cv.visitInsn(ATHROW);
cv.visitTryCatchBlock(readArgs, handler, handler, Type
.getInternalName(IOException.class));
if (needcastcheck) {
cv.visitTryCatchBlock(readArgs, handler, handler, Type
.getInternalName(ClassCastException.class));
}
// finally block
cv.visitLabel(closeInput);
cv.visitVarInsn(ASTORE, var.allocate("retAddress"));
cv.visitVarInsn(ALOAD, var.get("remotecall"));
cv.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteCall.class), "releaseInputStream", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
cv.visitVarInsn(RET, var.deallocate("retAddress"));
var.deallocate("toThrow");
// do the call using args stored as variables
cv.visitLabel(doCall);
cv.visitVarInsn(ALOAD, var.get("remoteobj"));
for (int i = 0; i < sig.length; i++)
cv.visitVarInsn(loadOpcode(sig[i]), var.deallocate(param(m, i)));
cv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(clazz), m
.getName(), Type.getMethodDescriptor(m));
Class returntype = m.getReturnType();
if (!returntype.equals(Void.TYPE)) {
cv.visitVarInsn(storeOpcode(returntype), var.allocate("result",
size(returntype)));
}
// write result to result stream
Label writeResult = new Label();
cv.visitLabel(writeResult);
cv.visitVarInsn(ALOAD, var.get("remotecall"));
cv.visitInsn(ICONST_1);
cv.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(RemoteCall.class), "getResultStream", Type
.getMethodDescriptor(Type.getType(ObjectOutput.class),
new Type[] { Type.BOOLEAN_TYPE }));
if (!returntype.equals(Void.TYPE)) {
// out.writeFoo(result)
cv.visitVarInsn(loadOpcode(returntype), var.deallocate("result"));
Class writeCls = returntype.isPrimitive() ? returntype
: Object.class;
cv.visitMethodInsn(INVOKEINTERFACE, Type
.getInternalName(ObjectOutput.class),
writeMethod(returntype), Type.getMethodDescriptor(
Type.VOID_TYPE,
new Type[] { Type.getType(writeCls) }));
}
cv.visitInsn(RETURN);
// throw new MarshalException
Label marshalHandler = new Label();
cv.visitLabel(marshalHandler);
cv.visitVarInsn(ASTORE, var.allocate("exception"));
cv.visitTypeInsn(NEW, typeArg(MarshalException.class));
cv.visitInsn(DUP);
cv.visitLdcInsn("error marshalling return");
cv.visitVarInsn(ALOAD, var.deallocate("exception"));
cv.visitMethodInsn(INVOKESPECIAL, Type
.getInternalName(MarshalException.class), "", Type
.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(String.class),
Type.getType(Exception.class) }));
cv.visitInsn(ATHROW);
cv.visitTryCatchBlock(writeResult, marshalHandler, marshalHandler, Type
.getInternalName(IOException.class));
}
private static String typeArg(Class cls) {
if (cls.isArray())
return Type.getDescriptor(cls);
return Type.getInternalName(cls);
}
private static String readMethod(Class cls) {
if (cls.equals(Void.TYPE))
throw new IllegalArgumentException("can not read void");
String method;
if (cls.equals(Boolean.TYPE))
method = "readBoolean";
else if (cls.equals(Byte.TYPE))
method = "readByte";
else if (cls.equals(Character.TYPE))
method = "readChar";
else if (cls.equals(Short.TYPE))
method = "readShort";
else if (cls.equals(Integer.TYPE))
method = "readInt";
else if (cls.equals(Long.TYPE))
method = "readLong";
else if (cls.equals(Float.TYPE))
method = "readFloat";
else if (cls.equals(Double.TYPE))
method = "readDouble";
else
method = "readObject";
return method;
}
private static String writeMethod(Class cls) {
if (cls.equals(Void.TYPE))
throw new IllegalArgumentException("can not read void");
String method;
if (cls.equals(Boolean.TYPE))
method = "writeBoolean";
else if (cls.equals(Byte.TYPE))
method = "writeByte";
else if (cls.equals(Character.TYPE))
method = "writeChar";
else if (cls.equals(Short.TYPE))
method = "writeShort";
else if (cls.equals(Integer.TYPE))
method = "writeInt";
else if (cls.equals(Long.TYPE))
method = "writeLong";
else if (cls.equals(Float.TYPE))
method = "writeFloat";
else if (cls.equals(Double.TYPE))
method = "writeDouble";
else
method = "writeObject";
return method;
}
private static int returnOpcode(Class cls) {
int returncode;
if (cls.equals(Boolean.TYPE))
returncode = IRETURN;
else if (cls.equals(Byte.TYPE))
returncode = IRETURN;
else if (cls.equals(Character.TYPE))
returncode = IRETURN;
else if (cls.equals(Short.TYPE))
returncode = IRETURN;
else if (cls.equals(Integer.TYPE))
returncode = IRETURN;
else if (cls.equals(Long.TYPE))
returncode = LRETURN;
else if (cls.equals(Float.TYPE))
returncode = FRETURN;
else if (cls.equals(Double.TYPE))
returncode = DRETURN;
else if (cls.equals(Void.TYPE))
returncode = RETURN;
else
returncode = ARETURN;
return returncode;
}
private static int loadOpcode(Class cls) {
if (cls.equals(Void.TYPE))
throw new IllegalArgumentException("can not load void");
int loadcode;
if (cls.equals(Boolean.TYPE))
loadcode = ILOAD;
else if (cls.equals(Byte.TYPE))
loadcode = ILOAD;
else if (cls.equals(Character.TYPE))
loadcode = ILOAD;
else if (cls.equals(Short.TYPE))
loadcode = ILOAD;
else if (cls.equals(Integer.TYPE))
loadcode = ILOAD;
else if (cls.equals(Long.TYPE))
loadcode = LLOAD;
else if (cls.equals(Float.TYPE))
loadcode = FLOAD;
else if (cls.equals(Double.TYPE))
loadcode = DLOAD;
else
loadcode = ALOAD;
return loadcode;
}
private static int storeOpcode(Class cls) {
if (cls.equals(Void.TYPE))
throw new IllegalArgumentException("can not load void");
int storecode;
if (cls.equals(Boolean.TYPE))
storecode = ISTORE;
else if (cls.equals(Byte.TYPE))
storecode = ISTORE;
else if (cls.equals(Character.TYPE))
storecode = ISTORE;
else if (cls.equals(Short.TYPE))
storecode = ISTORE;
else if (cls.equals(Integer.TYPE))
storecode = ISTORE;
else if (cls.equals(Long.TYPE))
storecode = LSTORE;
else if (cls.equals(Float.TYPE))
storecode = FSTORE;
else if (cls.equals(Double.TYPE))
storecode = DSTORE;
else
storecode = ASTORE;
return storecode;
}
private static String unboxMethod(Class primitive) {
if (!primitive.isPrimitive())
throw new IllegalArgumentException("can not unbox nonprimitive");
String method;
if (primitive.equals(Boolean.TYPE))
method = "booleanValue";
else if (primitive.equals(Byte.TYPE))
method = "byteValue";
else if (primitive.equals(Character.TYPE))
method = "charValue";
else if (primitive.equals(Short.TYPE))
method = "shortValue";
else if (primitive.equals(Integer.TYPE))
method = "intValue";
else if (primitive.equals(Long.TYPE))
method = "longValue";
else if (primitive.equals(Float.TYPE))
method = "floatValue";
else if (primitive.equals(Double.TYPE))
method = "doubleValue";
else
throw new IllegalStateException("unknown primitive class "
+ primitive);
return method;
}
public static Class box(Class cls) {
if (!cls.isPrimitive())
throw new IllegalArgumentException("can only box primitive");
Class box;
if (cls.equals(Boolean.TYPE))
box = Boolean.class;
else if (cls.equals(Byte.TYPE))
box = Byte.class;
else if (cls.equals(Character.TYPE))
box = Character.class;
else if (cls.equals(Short.TYPE))
box = Short.class;
else if (cls.equals(Integer.TYPE))
box = Integer.class;
else if (cls.equals(Long.TYPE))
box = Long.class;
else if (cls.equals(Float.TYPE))
box = Float.class;
else if (cls.equals(Double.TYPE))
box = Double.class;
else
throw new IllegalStateException("unknown primitive type " + cls);
return box;
}
private static int size(Class cls) {
if (cls.equals(Long.TYPE) || cls.equals(Double.TYPE))
return 2;
else
return 1;
}
/**
* Sort exceptions so the most general go last.
*/
private Class[] sortExceptions(Class[] except) {
for (int i = 0; i < except.length; i++) {
for (int j = i + 1; j < except.length; j++) {
if (except[i].isAssignableFrom(except[j])) {
Class tmp = except[i];
except[i] = except[j];
except[j] = tmp;
}
}
}
return (except);
}
/**
* Process the options until we find the first argument.
*/
private void parseOptions() {
for (;;) {
if (next >= args.length || args[next].charAt(0) != '-')
break;
String arg = args[next];
next++;
// Accept `--' options if they look long enough.
if (arg.length() > 3 && arg.charAt(0) == '-'
&& arg.charAt(1) == '-')
arg = arg.substring(1);
if (arg.equals("-keep"))
keep = true;
else if (arg.equals("-keepgenerated"))
keep = true;
else if (arg.equals("-v1.1")) {
need11Stubs = true;
need12Stubs = false;
} else if (arg.equals("-vcompat")) {
need11Stubs = true;
need12Stubs = true;
} else if (arg.equals("-v1.2")) {
need11Stubs = false;
need12Stubs = true;
} else if (arg.equals("-g")) {
} else if (arg.equals("-depend")) {
} else if (arg.equals("-nowarn")) {
} else if (arg.equals("-verbose"))
verbose = true;
else if (arg.equals("-nocompile"))
compile = false;
else if (arg.equals("-classpath")) {
classpath = args[next];
next++;
StringTokenizer st = new StringTokenizer(classpath,
File.pathSeparator);
URL[] u = new URL[st.countTokens()];
for (int i = 0; i < u.length; i++) {
String path = st.nextToken();
File f = new File(path);
try {
u[i] = f.toURL();
} catch (java.net.MalformedURLException mue) {
error("malformed classpath component " + path);
}
}
// Explicitely set the parent.
// AFAIK, by default, it's the system classloader
ClassLoader parent = RMIC.class.getClassLoader();
loader = new URLClassLoader(u, parent);
} else if (arg.equals("-help"))
usage();
else if (arg.equals("-version")) {
System.out.println("rmic ("
+ System.getProperty("java.vm.name") + ") "
+ System.getProperty("java.vm.version"));
System.out.println();
System.out
.println("Copyright 2002 Free Software Foundation, Inc.");
System.out
.println("This is free software; see the source for copying conditions. There is NO");
System.out
.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
System.exit(0);
} else if (arg.equals("-d")) {
destination = args[next];
next++;
} else if (arg.charAt(1) == 'J') {
} else
error("unrecognized option `" + arg + "'");
}
}
private void findRemoteMethods() {
List rmeths = new ArrayList();
for (Class cur = clazz; cur != null; cur = cur.getSuperclass()) {
Class[] interfaces = cur.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (java.rmi.Remote.class.isAssignableFrom(interfaces[i])) {
Class remoteInterface = interfaces[i];
// Check if the interface was already added
if (mRemoteInterfaces.contains(remoteInterface))
continue;
if (verbose)
System.out.println("[implements "
+ remoteInterface.getName() + "]");
// check if the methods declare RemoteExceptions
Method[] meths = remoteInterface.getMethods();
for (int j = 0; j < meths.length; j++) {
Method m = meths[j];
Class[] exs = m.getExceptionTypes();
boolean throwsRemote = false;
for (int k = 0; k < exs.length; k++) {
if (exs[k].isAssignableFrom(RemoteException.class))
throwsRemote = true;
}
if (!throwsRemote) {
logError("Method " + m
+ " does not throw a RemoteException");
continue;
}
rmeths.add(m);
}
mRemoteInterfaces.add(remoteInterface);
}
}
}
// intersect exceptions for doubly inherited methods
boolean[] skip = new boolean[rmeths.size()];
for (int i = 0; i < skip.length; i++)
skip[i] = false;
List methrefs = new ArrayList();
for (int i = 0; i < rmeths.size(); i++) {
if (skip[i])
continue;
Method current = (Method) rmeths.get(i);
MethodRef ref = new MethodRef(current);
for (int j = i + 1; j < rmeths.size(); j++) {
Method other = (Method) rmeths.get(j);
if (ref.isMatch(other)) {
ref.intersectExceptions(other);
skip[j] = true;
}
}
methrefs.add(ref);
}
// Convert into a MethodRef array and sort them
remotemethods = (MethodRef[]) methrefs.toArray(new MethodRef[methrefs
.size()]);
Arrays.sort(remotemethods);
}
/**
* Prints an error to System.err and increases the error count.
*
* @param theError
*/
private void logError(String theError) {
errorCount++;
System.err.println("error:" + theError);
}
private static void error(String message) {
System.err.println("rmic: " + message);
System.err.println("Try `rmic --help' for more information.");
System.exit(1);
}
private static void usage() {
System.out
.println("Usage: rmic [OPTION]... CLASS...\n"
+ "\n"
+ " -keep * Don't delete any intermediate files\n"
+ " -keepgenerated * Same as -keep\n"
+ " -v1.1 Java 1.1 style stubs only\n"
+ " -vcompat Java 1.1 & Java 1.2 stubs\n"
+ " -v1.2 Java 1.2 style stubs only\n"
+ " -g * Generated debugging information\n"
+ " -depend * Recompile out-of-date files\n"
+ " -nowarn * Suppress warning messages\n"
+ " -nocompile * Don't compile the generated files\n"
+ " -verbose Output what's going on\n"
+ " -classpath Use given path as classpath\n"
+ " -d Specify where to place generated classes\n"
+ " -J * Pass flag to Java\n"
+ " -help Print this help, then exit\n"
+ " -version Print version number, then exit\n"
+ "\n"
+ " * Option currently ignored\n"
+ "Long options can be used with `--option' form as well.");
System.exit(0);
}
private static String getPrettyName(Class cls) {
StringBuffer str = new StringBuffer();
for (int count = 0;; count++) {
if (!cls.isArray()) {
str.append(cls.getName());
for (; count > 0; count--)
str.append("[]");
return (str.toString());
}
cls = cls.getComponentType();
}
}
private static class MethodRef implements Comparable {
Method meth;
long hash;
List exceptions;
private String sig;
MethodRef(Method m) {
meth = m;
sig = Type.getMethodDescriptor(meth);
hash = getMethodHash(m);
// add exceptions removing subclasses
exceptions = removeSubclasses(m.getExceptionTypes());
}
public int compareTo(Object obj) {
MethodRef that = (MethodRef) obj;
int name = this.meth.getName().compareTo(that.meth.getName());
if (name == 0) {
return this.sig.compareTo(that.sig);
}
return name;
}
public boolean isMatch(Method m) {
if (!meth.getName().equals(m.getName()))
return false;
Class[] params1 = meth.getParameterTypes();
Class[] params2 = m.getParameterTypes();
if (params1.length != params2.length)
return false;
for (int i = 0; i < params1.length; i++)
if (!params1[i].equals(params2[i]))
return false;
return true;
}
private static List removeSubclasses(Class[] classes) {
List list = new ArrayList();
for (int i = 0; i < classes.length; i++) {
Class candidate = classes[i];
boolean add = true;
for (int j = 0; j < classes.length; j++) {
if (classes[j].equals(candidate))
continue;
else if (classes[j].isAssignableFrom(candidate))
add = false;
}
if (add)
list.add(candidate);
}
return list;
}
public void intersectExceptions(Method m) {
List incoming = removeSubclasses(m.getExceptionTypes());
List updated = new ArrayList();
for (int i = 0; i < exceptions.size(); i++) {
Class outer = (Class) exceptions.get(i);
boolean addOuter = false;
for (int j = 0; j < incoming.size(); j++) {
Class inner = (Class) incoming.get(j);
if (inner.equals(outer) || inner.isAssignableFrom(outer))
addOuter = true;
else if (outer.isAssignableFrom(inner))
updated.add(inner);
}
if (addOuter)
updated.add(outer);
}
exceptions = updated;
}
}
// XXX from RMIHashes (modified)
public static long getInterfaceHash(Class cls) {
return cls.hashCode();
/*
* 8.3 of RMI spec # (int) stub version number, always 1 # for each
* remote method, in order of operation number: * (UTF-8) remote method
* name * (UTF-8) remote method descriptor (see section 4.3.3 of JVMS) *
* for each declared exception, in lexicographic order of binary name: o
* (UTF-8) the name of the exception class
*/
}
// XXX from RMIHashes (modified)
public static long getMethodHash(Method meth) {
// Object Serialization Spec 8.3
try {
MessageDigest md = MessageDigest.getInstance("SHA");
// or:remove this statement: DigestOutputStream digest_out = new
// DigestOutputStream (nullOutputStream, md);
ByteArrayOutputStream digest_out = new ByteArrayOutputStream();
DataOutputStream data_out = new DataOutputStream(digest_out);
StringBuffer sbuf = new StringBuffer();
sbuf.append(meth.getName());
sbuf.append(Type.getMethodDescriptor(meth));
data_out.writeUTF(sbuf.toString());
data_out.flush();
data_out.close();
md.update(digest_out.toByteArray()); // or:remove this statement
byte[] sha = md.digest();
long result = 0;
int len = sha.length < 8 ? sha.length : 8;
for (int i = 0; i < len; i++)
result += (long) (sha[i] & 0xFF) << (8 * i);
return result;
} catch (Exception _) {
return -1L;
}
}
/**
* Generate a stub for the given classname and the given classloader
*
* @param className
* the name of the class
* @param classLoader
* the classloader to use to find the class.
* @return list of generated class with their name and associated bytecode.
* @throws RMICException
* if it fails
*/
public static List generateStubForClass(final String className,
final ClassLoader classLoader) throws RMICException {
List classInfos = new ArrayList();
// New object
RMIC rmic = new RMIC(null);
// Sets the loader
rmic.loader = classLoader;
// Init list
rmic.mRemoteInterfaces = new ArrayList();
// Analyze the class
try {
rmic.analyzeClass(className);
} catch (Exception e) {
throw new RMICException("Unable to analyze the class '" + className
+ "'", e);
}
// generate stub
try {
ClassInfo classInfo = rmic.generateStubData();
// add result
classInfos.add(classInfo);
} catch (IOException e) {
throw new RMICException("Unable to generate stub for the class '"
+ className + "'", e);
}
if (rmic.need11Stubs) {
try {
ClassInfo classInfo = rmic.generateSkelData();
// add result
classInfos.add(classInfo);
} catch (IOException e) {
throw new RMICException(
"Unable to generate skel for the class '" + className
+ "'", e);
}
}
return classInfos;
}
}