1 /* ClassRmicCompiler.java --
2 Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 package gnu.classpath.tools.rmic;
24 import gnu.java.rmi.server.RMIHashes;
25 import java.io.ByteArrayOutputStream;
26 import java.io.DataOutputStream;
28 import java.io.FileOutputStream;
29 import java.io.FileWriter;
30 import java.io.IOException;
31 import java.io.ObjectInput;
32 import java.io.ObjectOutput;
33 import java.io.PrintWriter;
34 import java.lang.reflect.Method;
36 import java.net.URLClassLoader;
37 import java.rmi.MarshalException;
38 import java.rmi.Remote;
39 import java.rmi.RemoteException;
40 import java.rmi.UnexpectedException;
41 import java.rmi.UnmarshalException;
42 import java.rmi.server.Operation;
43 import java.rmi.server.RemoteCall;
44 import java.rmi.server.RemoteObject;
45 import java.rmi.server.RemoteRef;
46 import java.rmi.server.RemoteStub;
47 import java.rmi.server.Skeleton;
48 import java.rmi.server.SkeletonMismatchException;
49 import java.security.MessageDigest;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.HashSet;
53 import java.util.Iterator;
54 import java.util.List;
56 import java.util.StringTokenizer;
57 import org.objectweb.asm.ClassVisitor;
58 import org.objectweb.asm.ClassWriter;
59 import org.objectweb.asm.MethodVisitor;
60 import org.objectweb.asm.Opcodes;
61 import org.objectweb.asm.Label;
62 import org.objectweb.asm.Type;
64 public class ClassRmicCompiler
65 implements RmicBackend
67 private String[] args;
69 private List errors = new ArrayList();
70 private boolean keep = false;
71 private boolean need11Stubs = true;
72 private boolean need12Stubs = true;
73 private boolean compile = true;
74 private boolean verbose;
75 private boolean noWrite;
76 private String destination;
77 private String classpath;
78 private ClassLoader loader;
79 private int errorCount = 0;
82 private String classname;
83 private String classInternalName;
84 private String fullclassname;
85 private MethodRef[] remotemethods;
86 private String stubname;
87 private String skelname;
88 private List mRemoteInterfaces;
91 * @return true if run was successful
93 public boolean run(String[] inputFiles)
97 if (next >= args.length)
100 for (int i = next; i < args.length; i++)
105 System.out.println("[Processing class " + args[i] + ".class]");
106 processClass(args[i].replace(File.separatorChar, '.'));
108 catch (IOException e)
112 catch (RMICException e)
117 if (errors.size() > 0)
119 for (Iterator it = errors.iterator(); it.hasNext(); )
121 Exception ex = (Exception) it.next();
126 return errorCount == 0;
129 private void processClass(String cls) throws IOException, RMICException
131 // reset class specific vars
134 classInternalName = null;
135 fullclassname = null;
136 remotemethods = null;
139 mRemoteInterfaces = new ArrayList();
147 private void analyzeClass(String cname)
151 System.out.println("[analyze class " + cname + "]");
152 int p = cname.lastIndexOf('.');
154 classname = cname.substring(p + 1);
157 fullclassname = cname;
166 public Exception getException()
168 return errors.size() == 0 ? null : (Exception) errors.get(0);
171 private void findClass()
174 ClassLoader cl = (loader == null
175 ? ClassLoader.getSystemClassLoader()
179 clazz = Class.forName(fullclassname, false, cl);
181 catch (ClassNotFoundException cnfe)
183 throw new RMICException
184 ("Class " + fullclassname + " not found in classpath", cnfe);
187 if (! Remote.class.isAssignableFrom(clazz))
189 throw new RMICException
190 ("Class " + clazz.getName()
191 + " does not implement a remote interface.");
195 private static Type[] typeArray(Class[] cls)
197 Type[] t = new Type[cls.length];
198 for (int i = 0; i < cls.length; i++)
200 t[i] = Type.getType(cls[i]);
206 private static String[] internalNameArray(Type[] t)
208 String[] s = new String[t.length];
209 for (int i = 0; i < t.length; i++)
211 s[i] = t[i].getInternalName();
217 private static String[] internalNameArray(Class[] c)
219 return internalNameArray(typeArray(c));
222 private static final String forName = "class$";
224 private static Object param(Method m, int argIndex)
226 List l = new ArrayList();
228 l.add(new Integer(argIndex));
232 private static void generateClassForNamer(ClassVisitor cls)
236 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC, forName,
237 Type.getMethodDescriptor
238 (Type.getType(Class.class), new Type[] { Type.getType(String.class) }),
241 Label start = new Label();
242 cv.visitLabel(start);
243 cv.visitVarInsn(Opcodes.ALOAD, 0);
245 (Opcodes.INVOKESTATIC,
246 Type.getInternalName(Class.class),
248 Type.getMethodDescriptor
249 (Type.getType(Class.class), new Type[] { Type.getType(String.class) }));
250 cv.visitInsn(Opcodes.ARETURN);
252 Label handler = new Label();
253 cv.visitLabel(handler);
254 cv.visitVarInsn(Opcodes.ASTORE, 1);
255 cv.visitTypeInsn(Opcodes.NEW, typeArg(NoClassDefFoundError.class));
256 cv.visitInsn(Opcodes.DUP);
257 cv.visitVarInsn(Opcodes.ALOAD, 1);
259 (Opcodes.INVOKEVIRTUAL,
260 Type.getInternalName(ClassNotFoundException.class),
262 Type.getMethodDescriptor(Type.getType(String.class), new Type[] {}));
264 (Opcodes.INVOKESPECIAL,
265 Type.getInternalName(NoClassDefFoundError.class),
267 Type.getMethodDescriptor
268 (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
269 cv.visitInsn(Opcodes.ATHROW);
270 cv.visitTryCatchBlock
271 (start, handler, handler,
272 Type.getInternalName(ClassNotFoundException.class));
273 cv.visitMaxs(-1, -1);
276 private void generateClassConstant(MethodVisitor cv, Class cls) {
277 if (cls.isPrimitive())
280 if (cls.equals(Boolean.TYPE))
281 boxCls = Boolean.class;
282 else if (cls.equals(Character.TYPE))
283 boxCls = Character.class;
284 else if (cls.equals(Byte.TYPE))
286 else if (cls.equals(Short.TYPE))
287 boxCls = Short.class;
288 else if (cls.equals(Integer.TYPE))
289 boxCls = Integer.class;
290 else if (cls.equals(Long.TYPE))
292 else if (cls.equals(Float.TYPE))
293 boxCls = Float.class;
294 else if (cls.equals(Double.TYPE))
295 boxCls = Double.class;
296 else if (cls.equals(Void.TYPE))
299 throw new IllegalArgumentException("unknown primitive type " + cls);
302 (Opcodes.GETSTATIC, Type.getInternalName(boxCls), "TYPE",
303 Type.getDescriptor(Class.class));
306 cv.visitLdcInsn(cls.getName());
308 (Opcodes.INVOKESTATIC, classInternalName, forName,
309 Type.getMethodDescriptor
310 (Type.getType(Class.class),
311 new Type[] { Type.getType(String.class) }));
314 private void generateClassArray(MethodVisitor code, Class[] classes)
316 code.visitLdcInsn(new Integer(classes.length));
317 code.visitTypeInsn(Opcodes.ANEWARRAY, typeArg(Class.class));
318 for (int i = 0; i < classes.length; i++)
320 code.visitInsn(Opcodes.DUP);
321 code.visitLdcInsn(new Integer(i));
322 generateClassConstant(code, classes[i]);
323 code.visitInsn(Opcodes.AASTORE);
327 private void fillOperationArray(MethodVisitor clinit)
330 clinit.visitLdcInsn(new Integer(remotemethods.length));
331 clinit.visitTypeInsn(Opcodes.ANEWARRAY, typeArg(Operation.class));
332 clinit.visitFieldInsn
333 (Opcodes.PUTSTATIC, classInternalName, "operations",
334 Type.getDescriptor(Operation[].class));
336 for (int i = 0; i < remotemethods.length; i++)
338 Method m = remotemethods[i].meth;
340 StringBuffer desc = new StringBuffer();
341 desc.append(getPrettyName(m.getReturnType()) + " ");
342 desc.append(m.getName() + "(");
345 Class[] sig = m.getParameterTypes();
346 for (int j = 0; j < sig.length; j++)
348 desc.append(getPrettyName(sig[j]));
349 if (j + 1 < sig.length)
353 // push operations array
354 clinit.visitFieldInsn
355 (Opcodes.GETSTATIC, classInternalName, "operations",
356 Type.getDescriptor(Operation[].class));
359 clinit.visitLdcInsn(new Integer(i));
361 // instantiate operation and leave a copy on the stack
362 clinit.visitTypeInsn(Opcodes.NEW, typeArg(Operation.class));
363 clinit.visitInsn(Opcodes.DUP);
364 clinit.visitLdcInsn(desc.toString());
365 clinit.visitMethodInsn
366 (Opcodes.INVOKESPECIAL,
367 Type.getInternalName(Operation.class),
369 Type.getMethodDescriptor
370 (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
372 // store in operations array
373 clinit.visitInsn(Opcodes.AASTORE);
377 private void generateStaticMethodObjs(MethodVisitor clinit)
379 for (int i = 0; i < remotemethods.length; i++)
381 Method m = remotemethods[i].meth;
384 * $method_<i>m.getName()</i>_<i>i</i> =
385 * <i>m.getDeclaringClass()</i>.class.getMethod
386 * (m.getName(), m.getParameterType())
388 String methodVar = "$method_" + m.getName() + "_" + i;
389 generateClassConstant(clinit, m.getDeclaringClass());
390 clinit.visitLdcInsn(m.getName());
391 generateClassArray(clinit, m.getParameterTypes());
392 clinit.visitMethodInsn
393 (Opcodes.INVOKEVIRTUAL,
394 Type.getInternalName(Class.class),
396 Type.getMethodDescriptor
397 (Type.getType(Method.class),
398 new Type[] { Type.getType(String.class),
399 Type.getType(Class[].class) }));
401 clinit.visitFieldInsn
402 (Opcodes.PUTSTATIC, classInternalName, methodVar,
403 Type.getDescriptor(Method.class));
407 private void generateStub()
410 stubname = fullclassname + "_Stub";
411 String stubclassname = classname + "_Stub";
412 File file = new File((destination == null ? "." : destination)
414 + stubname.replace('.', File.separatorChar)
418 System.out.println("[Generating class " + stubname + "]");
420 final ClassWriter stub = new ClassWriter(true);
421 classInternalName = stubname.replace('.', '/');
422 final String superInternalName =
423 Type.getType(RemoteStub.class).getInternalName();
425 String[] remoteInternalNames =
426 internalNameArray((Class[]) mRemoteInterfaces.toArray(new Class[] {}));
428 (Opcodes.V1_2, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, classInternalName,
429 null, superInternalName, remoteInternalNames);
434 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "serialVersionUID",
435 Type.LONG_TYPE.getDescriptor(), null, new Long(2L));
441 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL,
442 "interfaceHash", Type.LONG_TYPE.getDescriptor(), null,
443 new Long(RMIHashes.getInterfaceHash(clazz)));
448 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "useNewInvoke",
449 Type.BOOLEAN_TYPE.getDescriptor(), null, null);
453 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL,
454 "operations", Type.getDescriptor(Operation[].class), null, null);
457 // Set of method references.
460 for (int i = 0; i < remotemethods.length; i++)
462 Method m = remotemethods[i].meth;
463 String slotName = "$method_" + m.getName() + "_" + i;
465 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, slotName,
466 Type.getDescriptor(Method.class), null, null);
470 MethodVisitor clinit = stub.visitMethod
471 (Opcodes.ACC_STATIC, "<clinit>",
472 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
476 fillOperationArray(clinit);
478 clinit.visitInsn(Opcodes.RETURN);
484 Label begin = new Label();
486 // beginning of catch
487 Label handler = new Label();
488 clinit.visitLabel(begin);
490 // Initialize the methods references.
494 * RemoteRef.class.getMethod("invoke", new Class[] {
495 * Remote.class, Method.class, Object[].class, long.class })
497 generateClassConstant(clinit, RemoteRef.class);
498 clinit.visitLdcInsn("invoke");
500 (clinit, new Class[] { Remote.class, Method.class,
501 Object[].class, long.class });
502 clinit.visitMethodInsn
503 (Opcodes.INVOKEVIRTUAL,
504 Type.getInternalName(Class.class),
506 Type.getMethodDescriptor
507 (Type.getType(Method.class),
508 new Type[] { Type.getType(String.class),
509 Type.getType(Class[].class) }));
511 // useNewInvoke = true
512 clinit.visitInsn(Opcodes.ICONST_1);
513 clinit.visitFieldInsn
514 (Opcodes.PUTSTATIC, classInternalName, "useNewInvoke",
515 Type.BOOLEAN_TYPE.getDescriptor());
518 generateStaticMethodObjs(clinit);
521 clinit.visitInsn(Opcodes.RETURN);
522 clinit.visitLabel(handler);
525 // useNewInvoke = false
526 clinit.visitInsn(Opcodes.ICONST_0);
527 clinit.visitFieldInsn
528 (Opcodes.PUTSTATIC, classInternalName, "useNewInvoke",
529 Type.BOOLEAN_TYPE.getDescriptor());
530 clinit.visitInsn(Opcodes.RETURN);
534 // throw NoSuchMethodError
535 clinit.visitTypeInsn(Opcodes.NEW, typeArg(NoSuchMethodError.class));
536 clinit.visitInsn(Opcodes.DUP);
537 clinit.visitLdcInsn("stub class initialization failed");
538 clinit.visitMethodInsn
539 (Opcodes.INVOKESPECIAL,
540 Type.getInternalName(NoSuchMethodError.class),
542 Type.getMethodDescriptor
544 new Type[] { Type.getType(String.class) }));
545 clinit.visitInsn(Opcodes.ATHROW);
548 clinit.visitTryCatchBlock
549 (begin, handler, handler,
550 Type.getInternalName(NoSuchMethodException.class));
554 clinit.visitMaxs(-1, -1);
556 generateClassForNamer(stub);
561 // no arg public constructor
562 MethodVisitor code = stub.visitMethod
563 (Opcodes.ACC_PUBLIC, "<init>",
564 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}),
566 code.visitVarInsn(Opcodes.ALOAD, 0);
568 (Opcodes.INVOKESPECIAL, superInternalName, "<init>",
569 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
570 code.visitInsn(Opcodes.RETURN);
572 code.visitMaxs(-1, -1);
575 // public RemoteRef constructor
576 MethodVisitor constructor = stub.visitMethod
577 (Opcodes.ACC_PUBLIC, "<init>",
578 Type.getMethodDescriptor
579 (Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}),
581 constructor.visitVarInsn(Opcodes.ALOAD, 0);
582 constructor.visitVarInsn(Opcodes.ALOAD, 1);
583 constructor.visitMethodInsn
584 (Opcodes.INVOKESPECIAL, superInternalName, "<init>",
585 Type.getMethodDescriptor
586 (Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}));
587 constructor.visitInsn(Opcodes.RETURN);
588 constructor.visitMaxs(-1, -1);
590 // Method implementations
591 for (int i = 0; i < remotemethods.length; i++)
593 Method m = remotemethods[i].meth;
594 Class[] sig = m.getParameterTypes();
595 Class returntype = m.getReturnType();
596 Class[] except = sortExceptions
597 ((Class[]) remotemethods[i].exceptions.toArray(new Class[0]));
599 MethodVisitor code = stub.visitMethod
602 Type.getMethodDescriptor(Type.getType(returntype), typeArray(sig)),
604 internalNameArray(typeArray(except)));
606 final Variables var = new Variables();
608 // this and parameters are the declared vars
610 for (int j = 0; j < sig.length; j++)
611 var.declare(param(m, j), size(sig[j]));
613 Label methodTryBegin = new Label();
614 code.visitLabel(methodTryBegin);
618 Label oldInvoke = new Label();
621 // if not useNewInvoke jump to old invoke
623 (Opcodes.GETSTATIC, classInternalName, "useNewInvoke",
624 Type.getDescriptor(boolean.class));
625 code.visitJumpInsn(Opcodes.IFEQ, oldInvoke);
629 code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
631 (Opcodes.GETFIELD, Type.getInternalName(RemoteObject.class),
632 "ref", Type.getDescriptor(RemoteRef.class));
634 // "this" is first arg to invoke
635 code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
637 // method object is second arg to invoke
638 String methName = "$method_" + m.getName() + "_" + i;
640 (Opcodes.GETSTATIC, classInternalName, methName,
641 Type.getDescriptor(Method.class));
643 // args to remote method are third arg to invoke
645 code.visitInsn(Opcodes.ACONST_NULL);
648 // create arg Object[] (with boxed primitives) and push it
649 code.visitLdcInsn(new Integer(sig.length));
650 code.visitTypeInsn(Opcodes.ANEWARRAY, typeArg(Object.class));
652 var.allocate("argArray");
653 code.visitVarInsn(Opcodes.ASTORE, var.get("argArray"));
655 for (int j = 0; j < sig.length; j++)
657 int size = size(sig[j]);
658 int insn = loadOpcode(sig[j]);
659 Class box = sig[j].isPrimitive() ? box(sig[j]) : null;
661 code.visitVarInsn(Opcodes.ALOAD, var.get("argArray"));
662 code.visitLdcInsn(new Integer(j));
664 // put argument on stack
667 code.visitTypeInsn(Opcodes.NEW, typeArg(box));
668 code.visitInsn(Opcodes.DUP);
669 code.visitVarInsn(insn, var.get(param(m, j)));
671 (Opcodes.INVOKESPECIAL,
672 Type.getInternalName(box),
674 Type.getMethodDescriptor
676 new Type[] { Type.getType(sig[j]) }));
679 code.visitVarInsn(insn, var.get(param(m, j)));
681 code.visitInsn(Opcodes.AASTORE);
684 code.visitVarInsn(Opcodes.ALOAD, var.deallocate("argArray"));
687 // push remote operation opcode
688 code.visitLdcInsn(new Long(remotemethods[i].hash));
690 (Opcodes.INVOKEINTERFACE,
691 Type.getInternalName(RemoteRef.class),
693 Type.getMethodDescriptor
694 (Type.getType(Object.class),
695 new Type[] { Type.getType(Remote.class),
696 Type.getType(Method.class),
697 Type.getType(Object[].class),
700 if (! returntype.equals(Void.TYPE))
702 int retcode = returnOpcode(returntype);
704 returntype.isPrimitive() ? box(returntype) : null;
706 (Opcodes.CHECKCAST, typeArg(boxCls == null ? returntype : boxCls));
707 if (returntype.isPrimitive())
711 (Opcodes.INVOKEVIRTUAL,
712 Type.getType(boxCls).getInternalName(),
713 unboxMethod(returntype),
714 Type.getMethodDescriptor
715 (Type.getType(returntype), new Type[] {}));
718 code.visitInsn(retcode);
721 code.visitInsn(Opcodes.RETURN);
725 code.visitLabel(oldInvoke);
731 // this.ref.newCall(this, operations, index, interfaceHash)
732 code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
735 Type.getInternalName(RemoteObject.class),
737 Type.getDescriptor(RemoteRef.class));
739 // "this" is first arg to newCall
740 code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
742 // operations is second arg to newCall
744 (Opcodes.GETSTATIC, classInternalName, "operations",
745 Type.getDescriptor(Operation[].class));
747 // method index is third arg
748 code.visitLdcInsn(new Integer(i));
750 // interface hash is fourth arg
752 (Opcodes.GETSTATIC, classInternalName, "interfaceHash",
753 Type.LONG_TYPE.getDescriptor());
756 (Opcodes.INVOKEINTERFACE,
757 Type.getInternalName(RemoteRef.class),
759 Type.getMethodDescriptor
760 (Type.getType(RemoteCall.class),
761 new Type[] { Type.getType(RemoteObject.class),
762 Type.getType(Operation[].class),
766 // store call object on stack and leave copy on stack
767 var.allocate("call");
768 code.visitInsn(Opcodes.DUP);
769 code.visitVarInsn(Opcodes.ASTORE, var.get("call"));
771 Label beginArgumentTryBlock = new Label();
772 code.visitLabel(beginArgumentTryBlock);
774 // ObjectOutput out = call.getOutputStream();
776 (Opcodes.INVOKEINTERFACE,
777 Type.getInternalName(RemoteCall.class),
779 Type.getMethodDescriptor
780 (Type.getType(ObjectOutput.class), new Type[] {}));
782 for (int j = 0; j < sig.length; j++)
784 // dup the ObjectOutput
785 code.visitInsn(Opcodes.DUP);
787 // get j'th arg to remote method
788 code.visitVarInsn(loadOpcode(sig[j]), var.get(param(m, j)));
791 sig[j].isPrimitive() ? sig[j] : Object.class;
795 (Opcodes.INVOKEINTERFACE,
796 Type.getInternalName(ObjectOutput.class),
798 Type.getMethodDescriptor
800 new Type[] { Type.getType(argCls) }));
804 code.visitInsn(Opcodes.POP);
806 Label iohandler = new Label();
807 Label endArgumentTryBlock = new Label();
808 code.visitJumpInsn(Opcodes.GOTO, endArgumentTryBlock);
809 code.visitLabel(iohandler);
811 // throw new MarshalException(msg, ioexception);
812 code.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
813 code.visitTypeInsn(Opcodes.NEW, typeArg(MarshalException.class));
814 code.visitInsn(Opcodes.DUP);
815 code.visitLdcInsn("error marshalling arguments");
816 code.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
818 (Opcodes.INVOKESPECIAL,
819 Type.getInternalName(MarshalException.class),
821 Type.getMethodDescriptor
823 new Type[] { Type.getType(String.class),
824 Type.getType(Exception.class) }));
825 code.visitInsn(Opcodes.ATHROW);
827 code.visitLabel(endArgumentTryBlock);
828 code.visitTryCatchBlock
829 (beginArgumentTryBlock, iohandler, iohandler,
830 Type.getInternalName(IOException.class));
832 // this.ref.invoke(call)
833 code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
835 (Opcodes.GETFIELD, Type.getInternalName(RemoteObject.class),
836 "ref", Type.getDescriptor(RemoteRef.class));
837 code.visitVarInsn(Opcodes.ALOAD, var.get("call"));
839 (Opcodes.INVOKEINTERFACE,
840 Type.getInternalName(RemoteRef.class),
842 Type.getMethodDescriptor
844 new Type[] { Type.getType(RemoteCall.class) }));
846 // handle return value
847 boolean needcastcheck = false;
849 Label beginReturnTryCatch = new Label();
850 code.visitLabel(beginReturnTryCatch);
852 int returncode = returnOpcode(returntype);
854 if (! returntype.equals(Void.TYPE))
856 // call.getInputStream()
857 code.visitVarInsn(Opcodes.ALOAD, var.get("call"));
859 (Opcodes.INVOKEINTERFACE,
860 Type.getInternalName(RemoteCall.class),
862 Type.getMethodDescriptor
863 (Type.getType(ObjectInput.class), new Type[] {}));
866 returntype.isPrimitive() ? returntype : Object.class;
868 (Opcodes.INVOKEINTERFACE,
869 Type.getInternalName(ObjectInput.class),
870 readMethod(returntype),
871 Type.getMethodDescriptor
872 (Type.getType(readCls), new Type[] {}));
874 boolean castresult = false;
876 if (! returntype.isPrimitive())
878 if (! returntype.equals(Object.class))
881 needcastcheck = true;
885 code.visitTypeInsn(Opcodes.CHECKCAST, typeArg(returntype));
887 // leave result on stack for return
890 // this.ref.done(call)
891 code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
894 Type.getInternalName(RemoteObject.class),
896 Type.getDescriptor(RemoteRef.class));
897 code.visitVarInsn(Opcodes.ALOAD, var.deallocate("call"));
899 (Opcodes.INVOKEINTERFACE,
900 Type.getInternalName(RemoteRef.class),
902 Type.getMethodDescriptor
904 new Type[] { Type.getType(RemoteCall.class) }));
906 // return; or return result;
907 code.visitInsn(returncode);
910 Label handler = new Label();
911 code.visitLabel(handler);
912 code.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
914 // throw new UnmarshalException(msg, e)
915 code.visitTypeInsn(Opcodes.NEW, typeArg(UnmarshalException.class));
916 code.visitInsn(Opcodes.DUP);
917 code.visitLdcInsn("error unmarshalling return");
918 code.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
920 (Opcodes.INVOKESPECIAL,
921 Type.getInternalName(UnmarshalException.class),
923 Type.getMethodDescriptor
925 new Type[] { Type.getType(String.class),
926 Type.getType(Exception.class) }));
927 code.visitInsn(Opcodes.ATHROW);
929 Label endReturnTryCatch = new Label();
932 code.visitTryCatchBlock
933 (beginReturnTryCatch, handler, handler,
934 Type.getInternalName(IOException.class));
938 // catch ClassNotFoundException
939 code.visitTryCatchBlock
940 (beginReturnTryCatch, handler, handler,
941 Type.getInternalName(ClassNotFoundException.class));
945 Label rethrowHandler = new Label();
946 code.visitLabel(rethrowHandler);
947 // rethrow declared exceptions
948 code.visitInsn(Opcodes.ATHROW);
950 boolean needgeneral = true;
951 for (int j = 0; j < except.length; j++)
953 if (except[j] == Exception.class)
957 for (int j = 0; j < except.length; j++)
959 code.visitTryCatchBlock
960 (methodTryBegin, rethrowHandler, rethrowHandler,
961 Type.getInternalName(except[j]));
966 // rethrow unchecked exceptions
967 code.visitTryCatchBlock
968 (methodTryBegin, rethrowHandler, rethrowHandler,
969 Type.getInternalName(RuntimeException.class));
971 Label generalHandler = new Label();
972 code.visitLabel(generalHandler);
973 String msg = "undeclared checked exception";
975 // throw new java.rmi.UnexpectedException(msg, e)
976 code.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
977 code.visitTypeInsn(Opcodes.NEW, typeArg(UnexpectedException.class));
978 code.visitInsn(Opcodes.DUP);
979 code.visitLdcInsn(msg);
980 code.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
982 (Opcodes.INVOKESPECIAL,
983 Type.getInternalName(UnexpectedException.class),
985 Type.getMethodDescriptor
987 new Type [] { Type.getType(String.class),
988 Type.getType(Exception.class) }));
989 code.visitInsn(Opcodes.ATHROW);
991 code.visitTryCatchBlock
992 (methodTryBegin, rethrowHandler, generalHandler,
993 Type.getInternalName(Exception.class));
996 code.visitMaxs(-1, -1);
1000 byte[] classData = stub.toByteArray();
1005 if (file.getParentFile() != null)
1006 file.getParentFile().mkdirs();
1007 FileOutputStream fos = new FileOutputStream(file);
1008 fos.write(classData);
1014 private void generateSkel() throws IOException
1016 skelname = fullclassname + "_Skel";
1017 String skelclassname = classname + "_Skel";
1018 File file = new File(destination == null ? "" : destination
1020 + skelname.replace('.', File.separatorChar)
1023 System.out.println("[Generating class " + skelname + "]");
1025 final ClassWriter skel = new ClassWriter(true);
1026 classInternalName = skelname.replace('.', '/');
1028 (Opcodes.V1_1, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL,
1029 classInternalName, Type.getInternalName(Object.class), null,
1030 new String[] { Type.getType(Skeleton.class).getInternalName() });
1033 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "interfaceHash",
1034 Type.LONG_TYPE.getDescriptor(), null,
1035 new Long(RMIHashes.getInterfaceHash(clazz)));
1038 (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "operations",
1039 Type.getDescriptor(Operation[].class), null, null);
1041 MethodVisitor clinit = skel.visitMethod
1042 (Opcodes.ACC_STATIC, "<clinit>",
1043 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
1045 fillOperationArray(clinit);
1046 clinit.visitInsn(Opcodes.RETURN);
1048 clinit.visitMaxs(-1, -1);
1050 // no arg public constructor
1051 MethodVisitor init = skel.visitMethod
1052 (Opcodes.ACC_PUBLIC, "<init>",
1053 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
1054 init.visitVarInsn(Opcodes.ALOAD, 0);
1055 init.visitMethodInsn
1056 (Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>",
1057 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
1058 init.visitInsn(Opcodes.RETURN);
1059 init.visitMaxs(-1, -1);
1062 * public Operation[] getOperations()
1063 * returns a clone of the operations array
1065 MethodVisitor getOp = skel.visitMethod
1066 (Opcodes.ACC_PUBLIC, "getOperations",
1067 Type.getMethodDescriptor
1068 (Type.getType(Operation[].class), new Type[] {}),
1070 getOp.visitFieldInsn
1071 (Opcodes.GETSTATIC, classInternalName, "operations",
1072 Type.getDescriptor(Operation[].class));
1073 getOp.visitMethodInsn
1074 (Opcodes.INVOKEVIRTUAL, Type.getInternalName(Object.class),
1075 "clone", Type.getMethodDescriptor(Type.getType(Object.class),
1077 getOp.visitTypeInsn(Opcodes.CHECKCAST, typeArg(Operation[].class));
1078 getOp.visitInsn(Opcodes.ARETURN);
1079 getOp.visitMaxs(-1, -1);
1081 // public void dispatch(Remote, RemoteCall, int opnum, long hash)
1082 MethodVisitor dispatch = skel.visitMethod
1083 (Opcodes.ACC_PUBLIC,
1085 Type.getMethodDescriptor
1087 new Type[] { Type.getType(Remote.class),
1088 Type.getType(RemoteCall.class),
1089 Type.INT_TYPE, Type.LONG_TYPE }), null,
1090 new String[] { Type.getInternalName(Exception.class) });
1092 Variables var = new Variables();
1093 var.declare("this");
1094 var.declare("remoteobj");
1095 var.declare("remotecall");
1096 var.declare("opnum");
1097 var.declareWide("hash");
1101 * XXX it is unclear why there is handling of negative opnums
1103 dispatch.visitVarInsn(Opcodes.ILOAD, var.get("opnum"));
1104 Label nonNegativeOpnum = new Label();
1105 Label opnumSet = new Label();
1106 dispatch.visitJumpInsn(Opcodes.IFGE, nonNegativeOpnum);
1108 for (int i = 0; i < remotemethods.length; i++)
1110 // assign opnum if hash matches supplied hash
1111 dispatch.visitVarInsn(Opcodes.LLOAD, var.get("hash"));
1112 dispatch.visitLdcInsn(new Long(remotemethods[i].hash));
1113 Label notIt = new Label();
1114 dispatch.visitInsn(Opcodes.LCMP);
1115 dispatch.visitJumpInsn(Opcodes.IFNE, notIt);
1118 dispatch.visitLdcInsn(new Integer(i));
1119 dispatch.visitVarInsn(Opcodes.ISTORE, var.get("opnum"));
1120 dispatch.visitJumpInsn(Opcodes.GOTO, opnumSet);
1121 dispatch.visitLabel(notIt);
1124 // throw new SkeletonMismatchException
1125 Label mismatch = new Label();
1126 dispatch.visitJumpInsn(Opcodes.GOTO, mismatch);
1128 dispatch.visitLabel(nonNegativeOpnum);
1130 // if opnum is already set, check that the hash matches the interface
1131 dispatch.visitVarInsn(Opcodes.LLOAD, var.get("hash"));
1132 dispatch.visitFieldInsn
1133 (Opcodes.GETSTATIC, classInternalName,
1134 "interfaceHash", Type.LONG_TYPE.getDescriptor());
1135 dispatch.visitInsn(Opcodes.LCMP);
1136 dispatch.visitJumpInsn(Opcodes.IFEQ, opnumSet);
1138 dispatch.visitLabel(mismatch);
1139 dispatch.visitTypeInsn
1140 (Opcodes.NEW, typeArg(SkeletonMismatchException.class));
1141 dispatch.visitInsn(Opcodes.DUP);
1142 dispatch.visitLdcInsn("interface hash mismatch");
1143 dispatch.visitMethodInsn
1144 (Opcodes.INVOKESPECIAL,
1145 Type.getInternalName(SkeletonMismatchException.class),
1147 Type.getMethodDescriptor
1148 (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
1149 dispatch.visitInsn(Opcodes.ATHROW);
1151 // opnum has been set
1152 dispatch.visitLabel(opnumSet);
1154 dispatch.visitVarInsn(Opcodes.ALOAD, var.get("remoteobj"));
1155 dispatch.visitTypeInsn(Opcodes.CHECKCAST, typeArg(clazz));
1156 dispatch.visitVarInsn(Opcodes.ASTORE, var.get("remoteobj"));
1158 Label deflt = new Label();
1159 Label[] methLabels = new Label[remotemethods.length];
1160 for (int i = 0; i < methLabels.length; i++)
1161 methLabels[i] = new Label();
1164 dispatch.visitVarInsn(Opcodes.ILOAD, var.get("opnum"));
1165 dispatch.visitTableSwitchInsn
1166 (0, remotemethods.length - 1, deflt, methLabels);
1169 for (int i = 0; i < remotemethods.length; i++)
1171 dispatch.visitLabel(methLabels[i]);
1172 Method m = remotemethods[i].meth;
1173 generateMethodSkel(dispatch, m, var);
1176 dispatch.visitLabel(deflt);
1177 dispatch.visitTypeInsn(Opcodes.NEW, typeArg(UnmarshalException.class));
1178 dispatch.visitInsn(Opcodes.DUP);
1179 dispatch.visitLdcInsn("invalid method number");
1180 dispatch.visitMethodInsn
1181 (Opcodes.INVOKESPECIAL,
1182 Type.getInternalName(UnmarshalException.class),
1184 Type.getMethodDescriptor
1185 (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
1186 dispatch.visitInsn(Opcodes.ATHROW);
1188 dispatch.visitMaxs(-1, -1);
1191 byte[] classData = skel.toByteArray();
1196 if (file.getParentFile() != null)
1197 file.getParentFile().mkdirs();
1198 FileOutputStream fos = new FileOutputStream(file);
1199 fos.write(classData);
1205 private void generateMethodSkel(MethodVisitor cv, Method m, Variables var)
1207 Class[] sig = m.getParameterTypes();
1209 Label readArgs = new Label();
1210 cv.visitLabel(readArgs);
1212 boolean needcastcheck = false;
1214 // ObjectInput in = call.getInputStream();
1215 cv.visitVarInsn(Opcodes.ALOAD, var.get("remotecall"));
1217 (Opcodes.INVOKEINTERFACE,
1218 Type.getInternalName(RemoteCall.class), "getInputStream",
1219 Type.getMethodDescriptor
1220 (Type.getType(ObjectInput.class), new Type[] {}));
1221 cv.visitVarInsn(Opcodes.ASTORE, var.allocate("objectinput"));
1223 for (int i = 0; i < sig.length; i++)
1226 cv.visitVarInsn(Opcodes.ALOAD, var.get("objectinput"));
1228 Class readCls = sig[i].isPrimitive() ? sig[i] : Object.class;
1232 (Opcodes.INVOKEINTERFACE,
1233 Type.getInternalName(ObjectInput.class),
1235 Type.getMethodDescriptor
1236 (Type.getType(readCls), new Type [] {}));
1238 if (! sig[i].isPrimitive() && ! sig[i].equals(Object.class))
1240 needcastcheck = true;
1241 cv.visitTypeInsn(Opcodes.CHECKCAST, typeArg(sig[i]));
1244 // store arg in variable
1246 (storeOpcode(sig[i]), var.allocate(param(m, i), size(sig[i])));
1249 var.deallocate("objectinput");
1251 Label doCall = new Label();
1252 Label closeInput = new Label();
1254 cv.visitJumpInsn(Opcodes.JSR, closeInput);
1255 cv.visitJumpInsn(Opcodes.GOTO, doCall);
1257 // throw new UnmarshalException
1258 Label handler = new Label();
1259 cv.visitLabel(handler);
1260 cv.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
1261 cv.visitTypeInsn(Opcodes.NEW, typeArg(UnmarshalException.class));
1262 cv.visitInsn(Opcodes.DUP);
1263 cv.visitLdcInsn("error unmarshalling arguments");
1264 cv.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
1266 (Opcodes.INVOKESPECIAL,
1267 Type.getInternalName(UnmarshalException.class),
1269 Type.getMethodDescriptor
1270 (Type.VOID_TYPE, new Type[] { Type.getType(String.class),
1271 Type.getType(Exception.class) }));
1272 cv.visitVarInsn(Opcodes.ASTORE, var.allocate("toThrow"));
1273 cv.visitJumpInsn(Opcodes.JSR, closeInput);
1274 cv.visitVarInsn(Opcodes.ALOAD, var.get("toThrow"));
1275 cv.visitInsn(Opcodes.ATHROW);
1277 cv.visitTryCatchBlock
1278 (readArgs, handler, handler, Type.getInternalName(IOException.class));
1281 cv.visitTryCatchBlock
1282 (readArgs, handler, handler,
1283 Type.getInternalName(ClassCastException.class));
1287 cv.visitLabel(closeInput);
1288 cv.visitVarInsn(Opcodes.ASTORE, var.allocate("retAddress"));
1289 cv.visitVarInsn(Opcodes.ALOAD, var.get("remotecall"));
1291 (Opcodes.INVOKEINTERFACE,
1292 Type.getInternalName(RemoteCall.class),
1293 "releaseInputStream",
1294 Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
1295 cv.visitVarInsn(Opcodes.RET, var.deallocate("retAddress"));
1296 var.deallocate("toThrow");
1298 // do the call using args stored as variables
1299 cv.visitLabel(doCall);
1300 cv.visitVarInsn(Opcodes.ALOAD, var.get("remoteobj"));
1301 for (int i = 0; i < sig.length; i++)
1302 cv.visitVarInsn(loadOpcode(sig[i]), var.deallocate(param(m, i)));
1304 (Opcodes.INVOKEVIRTUAL, Type.getInternalName(clazz), m.getName(),
1305 Type.getMethodDescriptor(m));
1307 Class returntype = m.getReturnType();
1308 if (! returntype.equals(Void.TYPE))
1311 (storeOpcode(returntype), var.allocate("result", size(returntype)));
1314 // write result to result stream
1315 Label writeResult = new Label();
1316 cv.visitLabel(writeResult);
1317 cv.visitVarInsn(Opcodes.ALOAD, var.get("remotecall"));
1318 cv.visitInsn(Opcodes.ICONST_1);
1320 (Opcodes.INVOKEINTERFACE,
1321 Type.getInternalName(RemoteCall.class),
1323 Type.getMethodDescriptor
1324 (Type.getType(ObjectOutput.class),
1325 new Type[] { Type.BOOLEAN_TYPE }));
1327 if (! returntype.equals(Void.TYPE))
1329 // out.writeFoo(result)
1330 cv.visitVarInsn(loadOpcode(returntype), var.deallocate("result"));
1331 Class writeCls = returntype.isPrimitive() ? returntype : Object.class;
1333 (Opcodes.INVOKEINTERFACE,
1334 Type.getInternalName(ObjectOutput.class),
1335 writeMethod(returntype),
1336 Type.getMethodDescriptor
1337 (Type.VOID_TYPE, new Type[] { Type.getType(writeCls) }));
1340 cv.visitInsn(Opcodes.RETURN);
1342 // throw new MarshalException
1343 Label marshalHandler = new Label();
1344 cv.visitLabel(marshalHandler);
1345 cv.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
1346 cv.visitTypeInsn(Opcodes.NEW, typeArg(MarshalException.class));
1347 cv.visitInsn(Opcodes.DUP);
1348 cv.visitLdcInsn("error marshalling return");
1349 cv.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
1351 (Opcodes.INVOKESPECIAL,
1352 Type.getInternalName(MarshalException.class),
1354 Type.getMethodDescriptor
1355 (Type.VOID_TYPE, new Type[] { Type.getType(String.class),
1356 Type.getType(Exception.class) }));
1357 cv.visitInsn(Opcodes.ATHROW);
1358 cv.visitTryCatchBlock
1359 (writeResult, marshalHandler, marshalHandler,
1360 Type.getInternalName(IOException.class));
1363 private static String typeArg(Class cls)
1366 return Type.getDescriptor(cls);
1368 return Type.getInternalName(cls);
1371 private static String readMethod(Class cls)
1373 if (cls.equals(Void.TYPE))
1374 throw new IllegalArgumentException("can not read void");
1377 if (cls.equals(Boolean.TYPE))
1378 method = "readBoolean";
1379 else if (cls.equals(Byte.TYPE))
1380 method = "readByte";
1381 else if (cls.equals(Character.TYPE))
1382 method = "readChar";
1383 else if (cls.equals(Short.TYPE))
1384 method = "readShort";
1385 else if (cls.equals(Integer.TYPE))
1387 else if (cls.equals(Long.TYPE))
1388 method = "readLong";
1389 else if (cls.equals(Float.TYPE))
1390 method = "readFloat";
1391 else if (cls.equals(Double.TYPE))
1392 method = "readDouble";
1394 method = "readObject";
1399 private static String writeMethod(Class cls)
1401 if (cls.equals(Void.TYPE))
1402 throw new IllegalArgumentException("can not read void");
1405 if (cls.equals(Boolean.TYPE))
1406 method = "writeBoolean";
1407 else if (cls.equals(Byte.TYPE))
1408 method = "writeByte";
1409 else if (cls.equals(Character.TYPE))
1410 method = "writeChar";
1411 else if (cls.equals(Short.TYPE))
1412 method = "writeShort";
1413 else if (cls.equals(Integer.TYPE))
1414 method = "writeInt";
1415 else if (cls.equals(Long.TYPE))
1416 method = "writeLong";
1417 else if (cls.equals(Float.TYPE))
1418 method = "writeFloat";
1419 else if (cls.equals(Double.TYPE))
1420 method = "writeDouble";
1422 method = "writeObject";
1427 private static int returnOpcode(Class cls)
1430 if (cls.equals(Boolean.TYPE))
1431 returncode = Opcodes.IRETURN;
1432 else if (cls.equals(Byte.TYPE))
1433 returncode = Opcodes.IRETURN;
1434 else if (cls.equals(Character.TYPE))
1435 returncode = Opcodes.IRETURN;
1436 else if (cls.equals(Short.TYPE))
1437 returncode = Opcodes.IRETURN;
1438 else if (cls.equals(Integer.TYPE))
1439 returncode = Opcodes.IRETURN;
1440 else if (cls.equals(Long.TYPE))
1441 returncode = Opcodes.LRETURN;
1442 else if (cls.equals(Float.TYPE))
1443 returncode = Opcodes.FRETURN;
1444 else if (cls.equals(Double.TYPE))
1445 returncode = Opcodes.DRETURN;
1446 else if (cls.equals(Void.TYPE))
1447 returncode = Opcodes.RETURN;
1449 returncode = Opcodes.ARETURN;
1454 private static int loadOpcode(Class cls)
1456 if (cls.equals(Void.TYPE))
1457 throw new IllegalArgumentException("can not load void");
1460 if (cls.equals(Boolean.TYPE))
1461 loadcode = Opcodes.ILOAD;
1462 else if (cls.equals(Byte.TYPE))
1463 loadcode = Opcodes.ILOAD;
1464 else if (cls.equals(Character.TYPE))
1465 loadcode = Opcodes.ILOAD;
1466 else if (cls.equals(Short.TYPE))
1467 loadcode = Opcodes.ILOAD;
1468 else if (cls.equals(Integer.TYPE))
1469 loadcode = Opcodes.ILOAD;
1470 else if (cls.equals(Long.TYPE))
1471 loadcode = Opcodes.LLOAD;
1472 else if (cls.equals(Float.TYPE))
1473 loadcode = Opcodes.FLOAD;
1474 else if (cls.equals(Double.TYPE))
1475 loadcode = Opcodes.DLOAD;
1477 loadcode = Opcodes.ALOAD;
1482 private static int storeOpcode(Class cls)
1484 if (cls.equals(Void.TYPE))
1485 throw new IllegalArgumentException("can not load void");
1488 if (cls.equals(Boolean.TYPE))
1489 storecode = Opcodes.ISTORE;
1490 else if (cls.equals(Byte.TYPE))
1491 storecode = Opcodes.ISTORE;
1492 else if (cls.equals(Character.TYPE))
1493 storecode = Opcodes.ISTORE;
1494 else if (cls.equals(Short.TYPE))
1495 storecode = Opcodes.ISTORE;
1496 else if (cls.equals(Integer.TYPE))
1497 storecode = Opcodes.ISTORE;
1498 else if (cls.equals(Long.TYPE))
1499 storecode = Opcodes.LSTORE;
1500 else if (cls.equals(Float.TYPE))
1501 storecode = Opcodes.FSTORE;
1502 else if (cls.equals(Double.TYPE))
1503 storecode = Opcodes.DSTORE;
1505 storecode = Opcodes.ASTORE;
1510 private static String unboxMethod(Class primitive)
1512 if (! primitive.isPrimitive())
1513 throw new IllegalArgumentException("can not unbox nonprimitive");
1516 if (primitive.equals(Boolean.TYPE))
1517 method = "booleanValue";
1518 else if (primitive.equals(Byte.TYPE))
1519 method = "byteValue";
1520 else if (primitive.equals(Character.TYPE))
1521 method = "charValue";
1522 else if (primitive.equals(Short.TYPE))
1523 method = "shortValue";
1524 else if (primitive.equals(Integer.TYPE))
1525 method = "intValue";
1526 else if (primitive.equals(Long.TYPE))
1527 method = "longValue";
1528 else if (primitive.equals(Float.TYPE))
1529 method = "floatValue";
1530 else if (primitive.equals(Double.TYPE))
1531 method = "doubleValue";
1533 throw new IllegalStateException("unknown primitive class " + primitive);
1538 public static Class box(Class cls)
1540 if (! cls.isPrimitive())
1541 throw new IllegalArgumentException("can only box primitive");
1544 if (cls.equals(Boolean.TYPE))
1545 box = Boolean.class;
1546 else if (cls.equals(Byte.TYPE))
1548 else if (cls.equals(Character.TYPE))
1549 box = Character.class;
1550 else if (cls.equals(Short.TYPE))
1552 else if (cls.equals(Integer.TYPE))
1553 box = Integer.class;
1554 else if (cls.equals(Long.TYPE))
1556 else if (cls.equals(Float.TYPE))
1558 else if (cls.equals(Double.TYPE))
1561 throw new IllegalStateException("unknown primitive type " + cls);
1566 private static int size(Class cls) {
1567 if (cls.equals(Long.TYPE) || cls.equals(Double.TYPE))
1574 * Sort exceptions so the most general go last.
1576 private Class[] sortExceptions(Class[] except)
1578 for (int i = 0; i < except.length; i++)
1580 for (int j = i + 1; j < except.length; j++)
1582 if (except[i].isAssignableFrom(except[j]))
1584 Class tmp = except[i];
1585 except[i] = except[j];
1593 public void setup(boolean keep, boolean need11Stubs, boolean need12Stubs,
1594 boolean iiop, boolean poa, boolean debug, boolean warnings,
1595 boolean noWrite, boolean verbose, boolean force, String classpath,
1596 String bootclasspath, String extdirs, String outputDirectory)
1599 this.need11Stubs = need11Stubs;
1600 this.need12Stubs = need12Stubs;
1601 this.verbose = verbose;
1602 this.noWrite = noWrite;
1604 // Set up classpath.
1605 this.classpath = classpath;
1606 StringTokenizer st =
1607 new StringTokenizer(classpath, File.pathSeparator);
1608 URL[] u = new URL[st.countTokens()];
1609 for (int i = 0; i < u.length; i++)
1611 String path = st.nextToken();
1612 File f = new File(path);
1617 catch (java.net.MalformedURLException mue)
1619 logError("malformed classpath component " + path);
1623 loader = new URLClassLoader(u);
1625 destination = outputDirectory;
1628 private void findRemoteMethods()
1629 throws RMICException
1631 List rmeths = new ArrayList();
1632 for (Class cur = clazz; cur != null; cur = cur.getSuperclass())
1634 Class[] interfaces = cur.getInterfaces();
1635 for (int i = 0; i < interfaces.length; i++)
1637 if (java.rmi.Remote.class.isAssignableFrom(interfaces[i]))
1639 Class remoteInterface = interfaces[i];
1642 ("[implements " + remoteInterface.getName() + "]");
1644 // check if the methods declare RemoteExceptions
1645 Method[] meths = remoteInterface.getMethods();
1646 for (int j = 0; j < meths.length; j++)
1648 Method m = meths[j];
1649 Class[] exs = m.getExceptionTypes();
1651 boolean throwsRemote = false;
1652 for (int k = 0; k < exs.length; k++)
1654 if (exs[k].isAssignableFrom(RemoteException.class))
1655 throwsRemote = true;
1660 throw new RMICException
1661 ("Method " + m + " in interface " + remoteInterface
1662 + " does not throw a RemoteException");
1668 mRemoteInterfaces.add(remoteInterface);
1673 // intersect exceptions for doubly inherited methods
1674 boolean[] skip = new boolean[rmeths.size()];
1675 for (int i = 0; i < skip.length; i++)
1677 List methrefs = new ArrayList();
1678 for (int i = 0; i < rmeths.size(); i++)
1680 if (skip[i]) continue;
1681 Method current = (Method) rmeths.get(i);
1682 MethodRef ref = new MethodRef(current);
1683 for (int j = i+1; j < rmeths.size(); j++)
1685 Method other = (Method) rmeths.get(j);
1686 if (ref.isMatch(other))
1688 ref.intersectExceptions(other);
1695 // Convert into a MethodRef array and sort them
1696 remotemethods = (MethodRef[])
1697 methrefs.toArray(new MethodRef[methrefs.size()]);
1698 Arrays.sort(remotemethods);
1702 * Prints an error to System.err and increases the error count.
1704 private void logError(Exception theError)
1706 logError(theError.getMessage());
1708 theError.printStackTrace(System.err);
1712 * Prints an error to System.err and increases the error count.
1714 private void logError(String theError)
1717 System.err.println("error: " + theError);
1720 private static String getPrettyName(Class cls)
1722 StringBuffer str = new StringBuffer();
1723 for (int count = 0;; count++)
1725 if (! cls.isArray())
1727 str.append(cls.getName());
1728 for (; count > 0; count--)
1730 return (str.toString());
1732 cls = cls.getComponentType();
1736 private static class MethodRef
1737 implements Comparable
1744 MethodRef(Method m) {
1746 sig = Type.getMethodDescriptor(meth);
1747 hash = RMIHashes.getMethodHash(m);
1748 // add exceptions removing subclasses
1749 exceptions = removeSubclasses(m.getExceptionTypes());
1752 public int compareTo(Object obj) {
1753 MethodRef that = (MethodRef) obj;
1754 int name = this.meth.getName().compareTo(that.meth.getName());
1756 return this.sig.compareTo(that.sig);
1761 public boolean isMatch(Method m)
1763 if (!meth.getName().equals(m.getName()))
1766 Class[] params1 = meth.getParameterTypes();
1767 Class[] params2 = m.getParameterTypes();
1768 if (params1.length != params2.length)
1771 for (int i = 0; i < params1.length; i++)
1772 if (!params1[i].equals(params2[i])) return false;
1777 private static List removeSubclasses(Class[] classes)
1779 List list = new ArrayList();
1780 for (int i = 0; i < classes.length; i++)
1782 Class candidate = classes[i];
1784 for (int j = 0; j < classes.length; j++)
1786 if (classes[j].equals(candidate))
1788 else if (classes[j].isAssignableFrom(candidate))
1791 if (add) list.add(candidate);
1797 public void intersectExceptions(Method m)
1799 List incoming = removeSubclasses(m.getExceptionTypes());
1801 List updated = new ArrayList();
1803 for (int i = 0; i < exceptions.size(); i++)
1805 Class outer = (Class) exceptions.get(i);
1806 boolean addOuter = false;
1807 for (int j = 0; j < incoming.size(); j++)
1809 Class inner = (Class) incoming.get(j);
1811 if (inner.equals(outer) || inner.isAssignableFrom(outer))
1813 else if (outer.isAssignableFrom(inner))
1821 exceptions = updated;