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;
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(", ");
}
// 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 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
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(-1, -1);
// 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(-1, -1);
/*
* 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(-1, -1);
// 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(-1, -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;
}
}