2 Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.java.rmi.rmic;
41 import java.io.FileWriter;
42 import java.io.PrintWriter;
43 import java.io.IOException;
44 import java.lang.reflect.Method;
45 import java.lang.reflect.Modifier;
46 import java.util.HashSet;
47 import java.util.Iterator;
48 import java.util.Arrays;
49 import java.lang.Comparable;
50 import gnu.java.rmi.server.RMIHashes;
54 private String[] args;
56 private Exception exception;
58 private boolean keep = false;
59 private boolean need11Stubs = true;
60 private boolean need12Stubs = true;
61 private boolean compile = true;
62 private boolean verbose;
63 private String destination;
65 private PrintWriter out;
66 private TabbedWriter ctrl;
69 private String classname;
70 private String fullclassname;
71 private MethodRef[] remotemethods;
72 private String stubname;
73 private String skelname;
75 public RMIC(String[] a) {
79 public static void main(String args[]) {
80 RMIC r = new RMIC(args);
81 if (r.run() == false) {
82 Exception exception = r.getException();
83 if (exception != null) {
84 exception.printStackTrace();
92 public boolean run() {
94 if (next >= args.length) {
95 error("no class names found");
97 for (int i = next; i < args.length; i++) {
100 System.out.println("[Processing class " + args[i] + ".class]");
102 processClass(args[i]);
104 catch (Exception e) {
112 private boolean processClass(String classname) throws Exception {
113 analyzeClass(classname);
119 compile(stubname + ".java");
121 compile(skelname + ".java");
125 (new File(stubname + ".java")).delete();
127 (new File(skelname + ".java")).delete();
133 private void analyzeClass(String cname) throws Exception {
134 int p = cname.lastIndexOf('.');
136 classname = cname.substring(p+1);
141 fullclassname = cname;
143 HashSet rmeths = new HashSet();
145 for (Class cls = clazz; cls != null; cls = cls.getSuperclass()) {
146 // Keep going down the inheritence tree until we hit the system
147 if (cls.getName().startsWith("java.")) {
151 Method[] meths = cls.getDeclaredMethods();
152 for (int i = 0; i < meths.length; i++) {
153 // Only include public methods
154 int mods = meths[i].getModifiers();
155 if (Modifier.isPublic(mods) && !Modifier.isStatic(mods)) {
156 // Should check exceptions here. - XXX
159 rmeths.add(meths[i]);
164 // Convert into a MethodRef array and sort them
165 remotemethods = new MethodRef[rmeths.size()];
167 for (Iterator i = rmeths.iterator(); i.hasNext(); ) {
168 remotemethods[c++] = new MethodRef((Method)i.next());
170 Arrays.sort(remotemethods);
173 public Exception getException() {
177 private void findClass() throws ClassNotFoundException {
178 clazz = Class.forName(fullclassname);
181 private void generateStub() throws IOException {
182 stubname = classname + "_Stub";
183 ctrl = new TabbedWriter(new FileWriter(stubname + ".java"));
184 out = new PrintWriter(ctrl);
187 System.out.println("[Generating class " + stubname + ".java]");
190 out.println("// Stub class generated by rmic - DO NOT EDIT!");
192 if (fullclassname != classname) {
193 String pname = fullclassname.substring(0, fullclassname.lastIndexOf('.'));
194 out.println("package " + pname + ";");
198 out.print("public final class " + stubname);
200 out.println("extends java.rmi.server.RemoteStub");
202 // Output interfaces we implement
203 out.print("implements ");
204 Class[] ifaces = clazz.getInterfaces();
205 for (int i = 0; i < ifaces.length; i++) {
206 out.print(ifaces[i].getName());
207 if (i+1 < ifaces.length) {
218 out.println("private static final long serialVersionUID = 2L;");
222 // InterfaceHash - don't know how to calculate this - XXX
224 out.println("private static final long interfaceHash = " + RMIHashes.getInterfaceHash(clazz) + "L;");
227 out.println("private static boolean useNewInvoke;");
232 out.print("private static final java.rmi.server.Operation[] operations = {");
235 for (int i = 0; i < remotemethods.length; i++) {
236 Method m = remotemethods[i].meth;
237 out.print("new java.rmi.server.Operation(\"");
238 out.print(getPrettyName(m.getReturnType()) + " ");
239 out.print(m.getName() + "(");
241 Class[] sig = m.getParameterTypes();
242 for (int j = 0; j < sig.length; j++) {
243 out.print(getPrettyName(sig[j]));
244 if (j+1 < sig.length) {
249 if (i + 1 < remotemethods.length) {
258 // Set of method references.
260 for (int i = 0; i < remotemethods.length; i++) {
261 Method m = remotemethods[i].meth;
262 out.println("private static java.lang.reflect.Method $method_" + m.getName() + "_" + i + ";");
265 // Initialize the methods references.
267 out.print("static {");
274 out.println("java.rmi.server.RemoteRef.class.getMethod(\"invoke\", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class });");
275 out.println("useNewInvoke = true;");
278 for (int i = 0; i < remotemethods.length; i++) {
279 Method m = remotemethods[i].meth;
280 out.print("$method_" + m.getName() + "_" + i + " = ");
281 out.print(fullclassname + ".class.getMethod(\"" + m.getName() + "\"");
282 out.print(", new java.lang.Class[] {");
284 Class[] sig = m.getParameterTypes();
285 for (int j = 0; j < sig.length; j++) {
286 out.print(getPrettyName(sig[j]) + ".class");
287 if (j+1 < sig.length) {
295 out.print("catch (java.lang.NoSuchMethodException e) {");
298 out.print("useNewInvoke = false;");
301 out.print("throw new java.lang.NoSuchMethodError(\"stub class initialization failed\");");
314 out.print("public " + stubname + "() {");
316 out.print("super();");
322 out.print("public " + stubname + "(java.rmi.server.RemoteRef ref) {");
324 out.print("super(ref);");
329 // Method implementations
330 for (int i = 0; i < remotemethods.length; i++) {
331 Method m = remotemethods[i].meth;
332 Class[] sig = m.getParameterTypes();
333 Class returntype = m.getReturnType();
334 Class[] except = sortExceptions(m.getExceptionTypes());
337 out.print("public " + getPrettyName(returntype) + " " + m.getName() + "(");
338 for (int j = 0; j < sig.length; j++) {
339 out.print(getPrettyName(sig[j]));
340 out.print(" $param_" + j);
341 if (j+1 < sig.length) {
346 out.print("throws ");
347 for (int j = 0; j < except.length; j++) {
348 out.print(getPrettyName(except[j]));
349 if (j+1 < except.length) {
361 out.print("if (useNewInvoke) {");
364 if (returntype != Void.TYPE) {
365 out.print("java.lang.Object $result = ");
367 out.print("ref.invoke(this, $method_" + m.getName() + "_" + i + ", ");
368 if (sig.length == 0) {
372 out.print("new java.lang.Object[] {");
373 for (int j = 0; j < sig.length; j++) {
374 if (sig[j] == Boolean.TYPE) {
375 out.print("new java.lang.Boolean($param_" + j + ")");
377 else if (sig[j] == Byte.TYPE) {
378 out.print("new java.lang.Byte($param_" + j + ")");
380 else if (sig[j] == Character.TYPE) {
381 out.print("new java.lang.Character($param_" + j + ")");
383 else if (sig[j] == Short.TYPE) {
384 out.print("new java.lang.Short($param_" + j + ")");
386 else if (sig[j] == Integer.TYPE) {
387 out.print("new java.lang.Integer($param_" + j + ")");
389 else if (sig[j] == Long.TYPE) {
390 out.print("new java.lang.Long($param_" + j + ")");
392 else if (sig[j] == Float.TYPE) {
393 out.print("new java.lang.Float($param_" + j + ")");
395 else if (sig[j] == Double.TYPE) {
396 out.print("new java.lang.Double($param_" + j + ")");
399 out.print("$param_" + j);
401 if (j+1 < sig.length) {
407 out.print(Long.toString(remotemethods[i].hash) + "L");
410 if (returntype != Void.TYPE) {
412 out.print("return (");
413 if (returntype == Boolean.TYPE) {
414 out.print("((java.lang.Boolean)$result).booleanValue()");
416 else if (returntype == Byte.TYPE) {
417 out.print("((java.lang.Byte)$result).byteValue()");
419 else if (returntype == Character.TYPE) {
420 out.print("((java.lang.Character)$result).charValue()");
422 else if (returntype == Short.TYPE) {
423 out.print("((java.lang.Short)$result).shortValue()");
425 else if (returntype == Integer.TYPE) {
426 out.print("((java.lang.Integer)$result).intValue()");
428 else if (returntype == Long.TYPE) {
429 out.print("((java.lang.Long)$result).longValue()");
431 else if (returntype == Float.TYPE) {
432 out.print("((java.lang.Float)$result).floatValue()");
434 else if (returntype == Double.TYPE) {
435 out.print("((java.lang.Double)$result).doubleValue()");
438 out.print("(" + getPrettyName(returntype) + ")$result");
452 out.println("java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, " + i + ", interfaceHash);");
455 out.print("java.io.ObjectOutput out = call.getOutputStream();");
456 for (int j = 0; j < sig.length; j++) {
458 if (sig[j] == Boolean.TYPE) {
459 out.print("out.writeBoolean(");
461 else if (sig[j] == Byte.TYPE) {
462 out.print("out.writeByte(");
464 else if (sig[j] == Character.TYPE) {
465 out.print("out.writeChar(");
467 else if (sig[j] == Short.TYPE) {
468 out.print("out.writeShort(");
470 else if (sig[j] == Integer.TYPE) {
471 out.print("out.writeInt(");
473 else if (sig[j] == Long.TYPE) {
474 out.print("out.writeLong(");
476 else if (sig[j] == Float.TYPE) {
477 out.print("out.writeFloat(");
479 else if (sig[j] == Double.TYPE) {
480 out.print("out.writeDouble(");
483 out.print("out.writeObject(");
485 out.print("$param_" + j + ");");
489 out.print("catch (java.io.IOException e) {");
491 out.print("throw new java.rmi.MarshalException(\"error marshalling arguments\", e);");
494 out.println("ref.invoke(call);");
495 if (returntype != Void.TYPE) {
496 out.println(getPrettyName(returntype) + " $result;");
500 out.print("java.io.ObjectInput in = call.getInputStream();");
501 boolean needcastcheck = false;
502 if (returntype != Void.TYPE) {
504 out.print("$result = ");
505 if (returntype == Boolean.TYPE) {
506 out.print("in.readBoolean();");
508 else if (returntype == Byte.TYPE) {
509 out.print("in.readByte();");
511 else if (returntype == Character.TYPE) {
512 out.print("in.readChar();");
514 else if (returntype == Short.TYPE) {
515 out.print("in.readShort();");
517 else if (returntype == Integer.TYPE) {
518 out.print("in.readInt();");
520 else if (returntype == Long.TYPE) {
521 out.print("in.readLong();");
523 else if (returntype == Float.TYPE) {
524 out.print("in.readFloat();");
526 else if (returntype == Double.TYPE) {
527 out.print("in.readDouble();");
530 if (returntype != Object.class) {
531 out.print("(" + getPrettyName(returntype) + ")");
534 needcastcheck = true;
536 out.print("in.readObject();");
539 out.print("return ($result);");
543 out.print("catch (java.io.IOException e) {");
545 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");
549 out.print("catch (java.lang.ClassNotFoundException e) {");
551 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");
555 out.print("finally {");
557 out.print("ref.done(call);");
561 if (need12Stubs && need11Stubs) {
570 boolean needgeneral = true;
571 for (int j = 0; j < except.length; j++) {
573 out.print("catch (" + getPrettyName(except[j]) + " e) {");
575 out.print("throw e;");
578 if (except[j] == Exception.class) {
584 out.print("catch (java.lang.Exception e) {");
586 out.print("throw new java.rmi.UnexpectedException(\"undeclared checked exception\", e);");
602 private void generateSkel() throws IOException {
603 skelname = classname + "_Skel";
604 ctrl = new TabbedWriter(new FileWriter(skelname + ".java"));
605 out = new PrintWriter(ctrl);
608 System.out.println("[Generating class " + skelname + ".java]");
611 out.println("// Skel class generated by rmic - DO NOT EDIT!");
613 if (fullclassname != classname) {
614 String pname = fullclassname.substring(0, fullclassname.lastIndexOf('.'));
615 out.println("package " + pname + ";");
619 out.print("public final class " + skelname);
622 // Output interfaces we implement
623 out.print("implements java.rmi.server.Skeleton");
629 // Interface hash - don't know how to calculate this - XXX
630 out.println("private static final long interfaceHash = " + RMIHashes.getInterfaceHash(clazz) + "L;");
634 out.print("private static final java.rmi.server.Operation[] operations = {");
637 for (int i = 0; i < remotemethods.length; i++) {
638 Method m = remotemethods[i].meth;
639 out.print("new java.rmi.server.Operation(\"");
640 out.print(getPrettyName(m.getReturnType()) + " ");
641 out.print(m.getName() + "(");
643 Class[] sig = m.getParameterTypes();
644 for (int j = 0; j < sig.length; j++) {
645 out.print(getPrettyName(sig[j]));
646 if (j+1 < sig.length) {
651 if (i + 1 < remotemethods.length) {
660 // getOperations method
661 out.print("public java.rmi.server.Operation[] getOperations() {");
663 out.print("return ((java.rmi.server.Operation[]) operations.clone());");
670 out.print("public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {");
673 out.print("if (opnum < 0) {");
676 for (int i = 0; i < remotemethods.length; i++) {
677 out.print("if (hash == " + Long.toString(remotemethods[i].hash) + "L) {");
679 out.print("opnum = " + i + ";");
686 out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");
692 out.print("else if (hash != interfaceHash) {");
694 out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");
700 out.println(fullclassname + " server = (" + fullclassname + ")obj;");
701 out.println("switch (opnum) {");
704 for (int i = 0; i < remotemethods.length; i++) {
705 Method m = remotemethods[i].meth;
706 out.println("case " + i + ":");
710 Class[] sig = m.getParameterTypes();
711 for (int j = 0; j < sig.length; j++) {
712 out.print(getPrettyName(sig[j]));
713 out.println(" $param_" + j + ";");
717 boolean needcastcheck = false;
719 out.println("java.io.ObjectInput in = call.getInputStream();");
720 for (int j = 0; j < sig.length; j++) {
721 out.print("$param_" + j + " = ");
722 if (sig[j] == Boolean.TYPE) {
723 out.print("in.readBoolean();");
725 else if (sig[j] == Byte.TYPE) {
726 out.print("in.readByte();");
728 else if (sig[j] == Character.TYPE) {
729 out.print("in.readChar();");
731 else if (sig[j] == Short.TYPE) {
732 out.print("in.readShort();");
734 else if (sig[j] == Integer.TYPE) {
735 out.print("in.readInt();");
737 else if (sig[j] == Long.TYPE) {
738 out.print("in.readLong();");
740 else if (sig[j] == Float.TYPE) {
741 out.print("in.readFloat();");
743 else if (sig[j] == Double.TYPE) {
744 out.print("in.readDouble();");
747 if (sig[j] != Object.class) {
748 out.print("(" + getPrettyName(sig[j]) + ")");
749 needcastcheck = true;
751 out.print("in.readObject();");
757 out.print("catch (java.io.IOException e) {");
759 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");
763 out.print("catch (java.lang.ClassCastException e) {");
765 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");
769 out.print("finally {");
771 out.print("call.releaseInputStream();");
775 Class returntype = m.getReturnType();
776 if (returntype != Void.TYPE) {
777 out.print(getPrettyName(returntype) + " $result = ");
779 out.print("server." + m.getName() + "(");
780 for (int j = 0; j < sig.length; j++) {
781 out.print("$param_" + j);
782 if (j + 1 < sig.length) {
790 out.print("java.io.ObjectOutput out = call.getResultStream(true);");
791 if (returntype != Void.TYPE) {
793 if (returntype == Boolean.TYPE) {
794 out.print("out.writeBoolean($result);");
796 else if (returntype == Byte.TYPE) {
797 out.print("out.writeByte($result);");
799 else if (returntype == Character.TYPE) {
800 out.print("out.writeChar($result);");
802 else if (returntype == Short.TYPE) {
803 out.print("out.writeShort($result);");
805 else if (returntype == Integer.TYPE) {
806 out.print("out.writeInt($result);");
808 else if (returntype == Long.TYPE) {
809 out.print("out.writeLong($result);");
811 else if (returntype == Float.TYPE) {
812 out.print("out.writeFloat($result);");
814 else if (returntype == Double.TYPE) {
815 out.print("out.writeDouble($result);");
818 out.print("out.writeObject($result);");
823 out.print("catch (java.io.IOException e) {");
825 out.print("throw new java.rmi.MarshalException(\"error marshalling return\", e);");
835 out.print("default:");
837 out.print("throw new java.rmi.UnmarshalException(\"invalid method number\");");
850 private void compile(String name) throws Exception {
851 Compiler comp = Compiler.getInstance();
853 System.out.println("[Compiling class " + name + "]");
855 comp.setDestination(destination);
859 private static String getPrettyName(Class cls) {
860 StringBuffer str = new StringBuffer();
861 for (int count = 0;; count++) {
862 if (!cls.isArray()) {
863 str.append(cls.getName());
864 for (; count > 0; count--) {
867 return (str.toString());
869 cls = cls.getComponentType();
874 * Sort exceptions so the most general go last.
876 private Class[] sortExceptions(Class[] except) {
877 for (int i = 0; i < except.length; i++) {
878 for (int j = i+1; j < except.length; j++) {
879 if (except[i].isAssignableFrom(except[j])) {
880 Class tmp = except[i];
881 except[i] = except[j];
890 * Process the options until we find the first argument.
892 private void parseOptions() {
894 if (next >= args.length || args[next].charAt(0) != '-') {
897 String arg = args[next];
900 // Accept `--' options if they look long enough.
901 if (arg.length() > 3 && arg.charAt(0) == '-'
902 && arg.charAt(1) == '-')
903 arg = arg.substring(1);
905 if (arg.equals("-keep")) {
908 else if (arg.equals("-keepgenerated")) {
911 else if (arg.equals("-v1.1")) {
915 else if (arg.equals("-vcompat")) {
919 else if (arg.equals("-v1.2")) {
923 else if (arg.equals("-g")) {
925 else if (arg.equals("-depend")) {
927 else if (arg.equals("-nowarn")) {
929 else if (arg.equals("-verbose")) {
932 else if (arg.equals("-nocompile")) {
935 else if (arg.equals("-classpath")) {
938 else if (arg.equals("-help")) {
941 else if (arg.equals("-version")) {
942 System.out.println("rmic (GNU "
943 + System.getProperty("java.vm.name")
945 + System.getProperty("java.vm.version"));
946 System.out.println();
947 System.out.println("Copyright 1996, 1997, 1998, 1999, 2001, 2002 Free Software Foundation");
948 System.out.println("This is free software; see the source for copying conditions. There is NO");
949 System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
952 else if (arg.equals("-d")) {
953 destination = args[next];
956 else if (arg.charAt(1) == 'J') {
959 error("unrecognized option `" + arg + "'");
964 private static void error(String message) {
965 System.err.println("rmic: " + message);
966 System.err.println("Try `rmic --help' for more information.");
970 private static void usage() {
972 "Usage: rmic [OPTION]... CLASS...\n" +
974 " -keep Don't delete any intermediate files\n" +
975 " -keepgenerated Same as -keep\n" +
976 " -v1.1 Java 1.1 style stubs only\n" +
977 " -vcompat Java 1.1 & Java 1.2 stubs\n" +
978 " -v1.2 Java 1.2 style stubs only\n" +
979 " -g * Generated debugging information\n" +
980 " -depend * Recompile out-of-date files\n" +
981 " -nowarn * Suppress warning messages\n" +
982 " -nocompile Don't compile the generated files\n" +
983 " -verbose Output what's going on\n" +
984 " -classpath <path> * Use given path as classpath\n" +
985 " -d <directory> Specify where to place generated classes\n" +
986 " -J<flag> * Pass flag to Java\n" +
987 " -help Print this help, then exit\n" +
988 " -version Print version number, then exit\n" +
990 " * Option currently ignored\n" +
991 "Long options can be used with `--option' form as well."
996 static class MethodRef
997 implements Comparable {
1003 MethodRef(Method m) {
1005 // We match on the name - but what about overloading? - XXX
1007 hash = RMIHashes.getMethodHash(m);
1010 public int compareTo(Object obj) {
1011 MethodRef that = (MethodRef)obj;
1012 return (this.sig.compareTo(that.sig));