OSDN Git Service

* config/i386/i386.md (*sinxf2): Rename to *sinxf2_i387.
[pf3gnuchains/gcc-fork.git] / libjava / gnu / java / rmi / rmic / RMIC.java
1 /* RMIC.java --
2    Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
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)
10 any later version.
11
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.
16
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., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39
40 package gnu.java.rmi.rmic;
41
42 import gnu.java.rmi.server.RMIHashes;
43
44 import java.io.File;
45 import java.io.FileWriter;
46 import java.io.IOException;
47 import java.io.PrintWriter;
48 import java.lang.reflect.Method;
49 import java.net.MalformedURLException;
50 import java.net.URL;
51 import java.net.URLClassLoader;
52 import java.rmi.Remote;
53 import java.rmi.RemoteException;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.HashSet;
57 import java.util.Iterator;
58 import java.util.List;
59 import java.util.Set;
60 import java.util.StringTokenizer;
61
62
63 public class RMIC
64 {
65   private String[] args;
66   private int next;
67   private Exception exception;
68   private boolean keep = false;
69   private boolean need11Stubs = true;
70   private boolean need12Stubs = true;
71   private boolean compile = true;
72   private boolean verbose;
73   private String destination;
74   private PrintWriter out;
75   private TabbedWriter ctrl;
76   private Class clazz;
77   private String classname;
78   private String fullclassname;
79   private String fullstubname;
80   private String fullskelname;
81   private MethodRef[] remotemethods;
82   private String stubname;
83   private String skelname;
84   private ClassLoader loader;
85   private String classpath;
86   private int errorCount = 0;
87   private List mRemoteInterfaces;
88
89   public RMIC(String[] a)
90   {
91     args = a;
92   }
93
94   public static void main(String[] args)
95   {
96     RMIC r = new RMIC(args);
97     if (r.run() == false)
98       {
99         Exception e = r.getException();
100         if (e != null)
101           e.printStackTrace();
102         else
103           System.exit(1);
104       }
105   }
106
107   public boolean run()
108   {
109     parseOptions();
110     if (next >= args.length)
111       error("no class names found");
112     for (int i = next; i < args.length; i++)
113       {
114         try
115           {
116             if (verbose)
117               System.out.println("[Processing class " + args[i] + ".class]");
118             processClass(args[i].replace(File.separatorChar, '.'));
119           }
120         catch (Exception e)
121           {
122             exception = e;
123             return (false);
124           }
125       }
126     return (true);
127   }
128
129   private boolean processClass(String cls) throws Exception
130   {
131     // reset class specific vars
132     clazz = null;
133     classname = null;
134     fullclassname = null;
135     remotemethods = null;
136     stubname = null;
137     fullstubname = null;
138     skelname = null;
139     fullskelname = null;
140     mRemoteInterfaces = new ArrayList();
141
142     errorCount = 0;
143
144     analyzeClass(cls);
145
146     if (errorCount > 0)
147       System.exit(1);
148     generateStub();
149     if (need11Stubs)
150       generateSkel();
151     if (compile)
152       {
153         compile(fullstubname);
154         if (need11Stubs)
155           compile(fullskelname);
156       }
157     if (! keep)
158       {
159         (new File(fullstubname)).delete();
160         if (need11Stubs)
161           (new File(fullskelname)).delete();
162       }
163     return (true);
164   }
165
166   private void analyzeClass(String cname) throws Exception
167   {
168     if (verbose)
169       System.out.println("[analyze class " + cname + "]");
170     int p = cname.lastIndexOf('.');
171     if (p != -1)
172       classname = cname.substring(p + 1);
173     else
174       classname = cname;
175     fullclassname = cname;
176
177     findClass();
178     findRemoteMethods();
179   }
180
181   public Exception getException()
182   {
183     return (exception);
184   }
185
186   private void findClass() throws ClassNotFoundException
187   {
188     try
189       {
190         ClassLoader cl = (loader == null
191                           ? ClassLoader.getSystemClassLoader()
192                           : loader);
193         clazz = Class.forName(fullclassname, false, cl);
194       }
195     catch (ClassNotFoundException cnfe)
196       {
197         System.err.println(fullclassname + " not found in " + classpath);
198         throw new RuntimeException(cnfe);
199       }
200
201     if (! Remote.class.isAssignableFrom(clazz))
202       {
203         logError("Class " + clazz.getName() + " is not a remote object. "
204                  + "It does not implement an interface that is a "
205                  + "java.rmi.Remote-interface.");
206         throw new RuntimeException
207           ("Class " + clazz.getName() + " is not a remote object. "
208            + "It does not implement an interface that is a "
209            + "java.rmi.Remote-interface.");
210       }
211   }
212
213   private void generateStub() throws IOException
214   {
215     stubname = fullclassname + "_Stub";
216     String stubclassname = classname + "_Stub";
217     fullstubname = (destination == null ? "" : destination + File.separator)
218       + stubname.replace('.', File.separatorChar) + ".java";
219     File file = new File(fullstubname);
220     if (file.getParentFile() != null)
221       file.getParentFile().mkdirs();
222     ctrl =
223       new TabbedWriter(new FileWriter(file));
224     out = new PrintWriter(ctrl);
225
226     if (verbose)
227       System.out.println("[Generating class " + stubname + ".java]");
228
229     out.println("// Stub class generated by rmic - DO NOT EDIT!");
230     out.println();
231     if (fullclassname != classname)
232       {
233         String pname =
234           fullclassname.substring(0, fullclassname.lastIndexOf('.'));
235         out.println("package " + pname + ";");
236         out.println();
237       }
238
239     out.print("public final class " + stubclassname);
240     ctrl.indent();
241     out.println("extends java.rmi.server.RemoteStub");
242
243     // Output interfaces we implement
244     out.print("implements ");
245     Iterator iter = mRemoteInterfaces.iterator();
246     while (iter.hasNext())
247       {
248         /* Print remote interface. */
249         Class iface = (Class) iter.next();
250         out.print(iface.getName());
251
252         /* Print ", " if more remote interfaces follow. */
253         if (iter.hasNext())
254           out.print(", ");
255       }
256     ctrl.unindent();
257     out.print("{");
258     ctrl.indent();
259
260     // UID
261     if (need12Stubs)
262       {
263         out.println("private static final long serialVersionUID = 2L;");
264         out.println();
265       }
266
267     // InterfaceHash - don't know how to calculate this - XXX
268     if (need11Stubs)
269       {
270         out.println("private static final long interfaceHash = "
271                     + RMIHashes.getInterfaceHash(clazz) + "L;");
272         out.println();
273         if (need12Stubs)
274           {
275             out.println("private static boolean useNewInvoke;");
276             out.println();
277           }
278
279         // Operation table
280         out.print("private static final java.rmi.server.Operation[] operations = {");
281
282         ctrl.indent();
283         for (int i = 0; i < remotemethods.length; i++)
284           {
285             Method m = remotemethods[i].meth;
286             out.print("new java.rmi.server.Operation(\"");
287             out.print(getPrettyName(m.getReturnType()) + " ");
288             out.print(m.getName() + "(");
289             // Output signature
290             Class[] sig = m.getParameterTypes();
291             for (int j = 0; j < sig.length; j++)
292               {
293                 out.print(getPrettyName(sig[j]));
294                 if (j + 1 < sig.length)
295                   out.print(", ");
296               }
297             out.print(")\")");
298             if (i + 1 < remotemethods.length)
299               out.println(",");
300           }
301         ctrl.unindent();
302         out.println("};");
303         out.println();
304       }
305
306     // Set of method references.
307     if (need12Stubs)
308       {
309         for (int i = 0; i < remotemethods.length; i++)
310           {
311             Method m = remotemethods[i].meth;
312             out.println("private static java.lang.reflect.Method $method_"
313                         + m.getName() + "_" + i + ";");
314           }
315
316         // Initialize the methods references.
317         out.println();
318         out.print("static {");
319         ctrl.indent();
320
321         out.print("try {");
322         ctrl.indent();
323
324         if (need11Stubs)
325           {
326             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 });");
327             out.println("useNewInvoke = true;");
328           }
329
330         for (int i = 0; i < remotemethods.length; i++)
331           {
332             Method m = remotemethods[i].meth;
333             out.print("$method_" + m.getName() + "_" + i + " = ");
334             out.print(m.getDeclaringClass().getName() + ".class.getMethod(\""
335                       + m.getName() + "\"");
336             out.print(", new java.lang.Class[] {");
337             // Output signature
338             Class[] sig = m.getParameterTypes();
339             for (int j = 0; j < sig.length; j++)
340               {
341                 out.print(getPrettyName(sig[j]) + ".class");
342                 if (j + 1 < sig.length)
343                   out.print(", ");
344               }
345             out.println("});");
346           }
347         ctrl.unindent();
348         out.println("}");
349         out.print("catch (java.lang.NoSuchMethodException e) {");
350         ctrl.indent();
351         if (need11Stubs)
352           out.print("useNewInvoke = false;");
353         else
354           out.print("throw new java.lang.NoSuchMethodError(\"stub class initialization failed\");");
355
356         ctrl.unindent();
357         out.print("}");
358
359         ctrl.unindent();
360         out.println("}");
361         out.println();
362       }
363
364     // Constructors
365     if (need11Stubs)
366       {
367         out.print("public " + stubclassname + "() {");
368         ctrl.indent();
369         out.print("super();");
370         ctrl.unindent();
371         out.println("}");
372       }
373
374     if (need12Stubs)
375       {
376         out.print("public " + stubclassname
377                   + "(java.rmi.server.RemoteRef ref) {");
378         ctrl.indent();
379         out.print("super(ref);");
380         ctrl.unindent();
381         out.println("}");
382       }
383
384     // Method implementations
385     for (int i = 0; i < remotemethods.length; i++)
386       {
387         Method m = remotemethods[i].meth;
388         Class[] sig = m.getParameterTypes();
389         Class returntype = m.getReturnType();
390         Class[] except = sortExceptions(m.getExceptionTypes());
391
392         out.println();
393         out.print("public " + getPrettyName(returntype) + " " + m.getName()
394                   + "(");
395         for (int j = 0; j < sig.length; j++)
396           {
397             out.print(getPrettyName(sig[j]));
398             out.print(" $param_" + j);
399             if (j + 1 < sig.length)
400               out.print(", ");
401           }
402         out.print(") ");
403         out.print("throws ");
404         for (int j = 0; j < except.length; j++)
405           {
406             out.print(getPrettyName(except[j]));
407             if (j + 1 < except.length)
408               out.print(", ");
409           }
410         out.print(" {");
411         ctrl.indent();
412
413         out.print("try {");
414         ctrl.indent();
415
416         if (need12Stubs)
417           {
418             if (need11Stubs)
419               {
420                 out.print("if (useNewInvoke) {");
421                 ctrl.indent();
422               }
423             if (returntype != Void.TYPE)
424               out.print("java.lang.Object $result = ");
425             out.print("ref.invoke(this, $method_" + m.getName() + "_" + i
426                       + ", ");
427             if (sig.length == 0)
428               out.print("null, ");
429             else
430               {
431                 out.print("new java.lang.Object[] {");
432                 for (int j = 0; j < sig.length; j++)
433                   {
434                     if (sig[j] == Boolean.TYPE)
435                       out.print("new java.lang.Boolean($param_" + j + ")");
436                     else if (sig[j] == Byte.TYPE)
437                       out.print("new java.lang.Byte($param_" + j + ")");
438                     else if (sig[j] == Character.TYPE)
439                       out.print("new java.lang.Character($param_" + j + ")");
440                     else if (sig[j] == Short.TYPE)
441                       out.print("new java.lang.Short($param_" + j + ")");
442                     else if (sig[j] == Integer.TYPE)
443                       out.print("new java.lang.Integer($param_" + j + ")");
444                     else if (sig[j] == Long.TYPE)
445                       out.print("new java.lang.Long($param_" + j + ")");
446                     else if (sig[j] == Float.TYPE)
447                       out.print("new java.lang.Float($param_" + j + ")");
448                     else if (sig[j] == Double.TYPE)
449                       out.print("new java.lang.Double($param_" + j + ")");
450                     else
451                       out.print("$param_" + j);
452                     if (j + 1 < sig.length)
453                       out.print(", ");
454                   }
455                 out.print("}, ");
456               }
457             out.print(Long.toString(remotemethods[i].hash) + "L");
458             out.print(");");
459
460             if (returntype != Void.TYPE)
461               {
462                 out.println();
463                 out.print("return (");
464                 if (returntype == Boolean.TYPE)
465                   out.print("((java.lang.Boolean)$result).booleanValue()");
466                 else if (returntype == Byte.TYPE)
467                   out.print("((java.lang.Byte)$result).byteValue()");
468                 else if (returntype == Character.TYPE)
469                   out.print("((java.lang.Character)$result).charValue()");
470                 else if (returntype == Short.TYPE)
471                   out.print("((java.lang.Short)$result).shortValue()");
472                 else if (returntype == Integer.TYPE)
473                   out.print("((java.lang.Integer)$result).intValue()");
474                 else if (returntype == Long.TYPE)
475                   out.print("((java.lang.Long)$result).longValue()");
476                 else if (returntype == Float.TYPE)
477                   out.print("((java.lang.Float)$result).floatValue()");
478                 else if (returntype == Double.TYPE)
479                   out.print("((java.lang.Double)$result).doubleValue()");
480                 else
481                   out.print("(" + getPrettyName(returntype) + ")$result");
482                 out.print(");");
483               }
484
485             if (need11Stubs)
486               {
487                 ctrl.unindent();
488                 out.println("}");
489                 out.print("else {");
490                 ctrl.indent();
491               }
492           }
493
494         if (need11Stubs)
495           {
496             out.println("java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, "
497                         + i + ", interfaceHash);");
498             out.print("try {");
499             ctrl.indent();
500             out.print("java.io.ObjectOutput out = call.getOutputStream();");
501             for (int j = 0; j < sig.length; j++)
502               {
503                 out.println();
504                 if (sig[j] == Boolean.TYPE)
505                   out.print("out.writeBoolean(");
506                 else if (sig[j] == Byte.TYPE)
507                   out.print("out.writeByte(");
508                 else if (sig[j] == Character.TYPE)
509                   out.print("out.writeChar(");
510                 else if (sig[j] == Short.TYPE)
511                   out.print("out.writeShort(");
512                 else if (sig[j] == Integer.TYPE)
513                   out.print("out.writeInt(");
514                 else if (sig[j] == Long.TYPE)
515                   out.print("out.writeLong(");
516                 else if (sig[j] == Float.TYPE)
517                   out.print("out.writeFloat(");
518                 else if (sig[j] == Double.TYPE)
519                   out.print("out.writeDouble(");
520                 else
521                   out.print("out.writeObject(");
522                 out.print("$param_" + j + ");");
523               }
524             ctrl.unindent();
525             out.println("}");
526             out.print("catch (java.io.IOException e) {");
527             ctrl.indent();
528             out.print("throw new java.rmi.MarshalException(\"error marshalling arguments\", e);");
529             ctrl.unindent();
530             out.println("}");
531             out.println("ref.invoke(call);");
532             if (returntype != Void.TYPE)
533               out.println(getPrettyName(returntype) + " $result;");
534             out.print("try {");
535             ctrl.indent();
536             out.print("java.io.ObjectInput in = call.getInputStream();");
537             boolean needcastcheck = false;
538             if (returntype != Void.TYPE)
539               {
540                 out.println();
541                 out.print("$result = ");
542                 if (returntype == Boolean.TYPE)
543                   out.print("in.readBoolean();");
544                 else if (returntype == Byte.TYPE)
545                   out.print("in.readByte();");
546                 else if (returntype == Character.TYPE)
547                   out.print("in.readChar();");
548                 else if (returntype == Short.TYPE)
549                   out.print("in.readShort();");
550                 else if (returntype == Integer.TYPE)
551                   out.print("in.readInt();");
552                 else if (returntype == Long.TYPE)
553                   out.print("in.readLong();");
554                 else if (returntype == Float.TYPE)
555                   out.print("in.readFloat();");
556                 else if (returntype == Double.TYPE)
557                   out.print("in.readDouble();");
558                 else
559                   {
560                     if (returntype != Object.class)
561                       out.print("(" + getPrettyName(returntype) + ")");
562                     else
563                       needcastcheck = true;
564                     out.print("in.readObject();");
565                   }
566                 out.println();
567                 out.print("return ($result);");
568               }
569             ctrl.unindent();
570             out.println("}");
571             out.print("catch (java.io.IOException e) {");
572             ctrl.indent();
573             out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");
574             ctrl.unindent();
575             out.println("}");
576             if (needcastcheck)
577               {
578                 out.print("catch (java.lang.ClassNotFoundException e) {");
579                 ctrl.indent();
580                 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");
581                 ctrl.unindent();
582                 out.println("}");
583               }
584             out.print("finally {");
585             ctrl.indent();
586             out.print("ref.done(call);");
587             ctrl.unindent();
588             out.print("}");
589
590             if (need12Stubs && need11Stubs)
591               {
592                 ctrl.unindent();
593                 out.print("}");
594               }
595           }
596
597         ctrl.unindent();
598         out.print("}");
599
600         boolean needgeneral = true;
601         for (int j = 0; j < except.length; j++)
602           {
603             out.println();
604             out.print("catch (" + getPrettyName(except[j]) + " e) {");
605             ctrl.indent();
606             out.print("throw e;");
607             ctrl.unindent();
608             out.print("}");
609             if (except[j] == Exception.class)
610               needgeneral = false;
611           }
612         if (needgeneral)
613           {
614             out.println();
615             out.print("catch (java.lang.Exception e) {");
616             ctrl.indent();
617             out.print("throw new java.rmi.UnexpectedException(\"undeclared checked exception\", e);");
618             ctrl.unindent();
619             out.print("}");
620           }
621
622         ctrl.unindent();
623         out.print("}");
624         out.println();
625       }
626
627     ctrl.unindent();
628     out.println("}");
629
630     out.close();
631   }
632
633   private void generateSkel() throws IOException
634   {
635     skelname = fullclassname + "_Skel";
636     String skelclassname = classname + "_Skel";
637     fullskelname = (destination == null ? "" : destination + File.separator)
638       + skelname.replace('.', File.separatorChar) + ".java";
639     File file = new File(fullskelname);
640     if (file.getParentFile() != null)
641       file.getParentFile().mkdirs();
642     ctrl =
643       new TabbedWriter(new FileWriter(file));
644     out = new PrintWriter(ctrl);
645
646     if (verbose)
647       System.out.println("[Generating class " + skelname + ".java]");
648
649     out.println("// Skel class generated by rmic - DO NOT EDIT!");
650     out.println();
651     if (fullclassname != classname)
652       {
653         String pname =
654           fullclassname.substring(0, fullclassname.lastIndexOf('.'));
655         out.println("package " + pname + ";");
656         out.println();
657       }
658
659     out.print("public final class " + skelclassname);
660     ctrl.indent();
661
662     // Output interfaces we implement
663     out.print("implements java.rmi.server.Skeleton");
664
665     ctrl.unindent();
666     out.print("{");
667     ctrl.indent();
668
669     // Interface hash - don't know how to calculate this - XXX
670     out.println("private static final long interfaceHash = "
671                 + RMIHashes.getInterfaceHash(clazz) + "L;");
672     out.println();
673
674     // Operation table
675     out.print("private static final java.rmi.server.Operation[] operations = {");
676
677     ctrl.indent();
678     for (int i = 0; i < remotemethods.length; i++)
679       {
680         Method m = remotemethods[i].meth;
681         out.print("new java.rmi.server.Operation(\"");
682         out.print(getPrettyName(m.getReturnType()) + " ");
683         out.print(m.getName() + "(");
684         // Output signature
685         Class[] sig = m.getParameterTypes();
686         for (int j = 0; j < sig.length; j++)
687           {
688             out.print(getPrettyName(sig[j]));
689             if (j + 1 < sig.length)
690               out.print(", ");
691           }
692         out.print("\")");
693         if (i + 1 < remotemethods.length)
694           out.println(",");
695       }
696     ctrl.unindent();
697     out.println("};");
698
699     out.println();
700
701     // getOperations method
702     out.print("public java.rmi.server.Operation[] getOperations() {");
703     ctrl.indent();
704     out.print("return ((java.rmi.server.Operation[]) operations.clone());");
705     ctrl.unindent();
706     out.println("}");
707
708     out.println();
709
710     // Dispatch method
711     out.print("public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {");
712     ctrl.indent();
713
714     out.print("if (opnum < 0) {");
715     ctrl.indent();
716
717     for (int i = 0; i < remotemethods.length; i++)
718       {
719         out.print("if (hash == " + Long.toString(remotemethods[i].hash)
720                   + "L) {");
721         ctrl.indent();
722         out.print("opnum = " + i + ";");
723         ctrl.unindent();
724         out.println("}");
725         out.print("else ");
726       }
727     out.print("{");
728     ctrl.indent();
729     out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");
730     ctrl.unindent();
731     out.print("}");
732
733     ctrl.unindent();
734     out.println("}");
735     out.print("else if (hash != interfaceHash) {");
736     ctrl.indent();
737     out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");
738     ctrl.unindent();
739     out.println("}");
740
741     out.println();
742
743     out.println(fullclassname + " server = (" + fullclassname + ")obj;");
744     out.println("switch (opnum) {");
745
746     // Method dispatch
747     for (int i = 0; i < remotemethods.length; i++)
748       {
749         Method m = remotemethods[i].meth;
750         out.println("case " + i + ":");
751         out.print("{");
752         ctrl.indent();
753
754         Class[] sig = m.getParameterTypes();
755         for (int j = 0; j < sig.length; j++)
756           {
757             out.print(getPrettyName(sig[j]));
758             out.println(" $param_" + j + ";");
759           }
760
761         out.print("try {");
762         boolean needcastcheck = false;
763         ctrl.indent();
764         out.println("java.io.ObjectInput in = call.getInputStream();");
765         for (int j = 0; j < sig.length; j++)
766           {
767             out.print("$param_" + j + " = ");
768             if (sig[j] == Boolean.TYPE)
769               out.print("in.readBoolean();");
770             else if (sig[j] == Byte.TYPE)
771               out.print("in.readByte();");
772             else if (sig[j] == Character.TYPE)
773               out.print("in.readChar();");
774             else if (sig[j] == Short.TYPE)
775               out.print("in.readShort();");
776             else if (sig[j] == Integer.TYPE)
777               out.print("in.readInt();");
778             else if (sig[j] == Long.TYPE)
779               out.print("in.readLong();");
780             else if (sig[j] == Float.TYPE)
781               out.print("in.readFloat();");
782             else if (sig[j] == Double.TYPE)
783               out.print("in.readDouble();");
784             else
785               {
786                 if (sig[j] != Object.class)
787                   {
788                     out.print("(" + getPrettyName(sig[j]) + ")");
789                     needcastcheck = true;
790                   }
791                 out.print("in.readObject();");
792               }
793             out.println();
794           }
795         ctrl.unindent();
796         out.println("}");
797         out.print("catch (java.io.IOException e) {");
798         ctrl.indent();
799         out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");
800         ctrl.unindent();
801         out.println("}");
802         if (needcastcheck)
803           {
804             out.print("catch (java.lang.ClassCastException e) {");
805             ctrl.indent();
806             out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");
807             ctrl.unindent();
808             out.println("}");
809           }
810         out.print("finally {");
811         ctrl.indent();
812         out.print("call.releaseInputStream();");
813         ctrl.unindent();
814         out.println("}");
815
816         Class returntype = m.getReturnType();
817         if (returntype != Void.TYPE)
818           out.print(getPrettyName(returntype) + " $result = ");
819         out.print("server." + m.getName() + "(");
820         for (int j = 0; j < sig.length; j++)
821           {
822             out.print("$param_" + j);
823             if (j + 1 < sig.length)
824               out.print(", ");
825           }
826         out.println(");");
827
828         out.print("try {");
829         ctrl.indent();
830         out.print("java.io.ObjectOutput out = call.getResultStream(true);");
831         if (returntype != Void.TYPE)
832           {
833             out.println();
834             if (returntype == Boolean.TYPE)
835               out.print("out.writeBoolean($result);");
836             else if (returntype == Byte.TYPE)
837               out.print("out.writeByte($result);");
838             else if (returntype == Character.TYPE)
839               out.print("out.writeChar($result);");
840             else if (returntype == Short.TYPE)
841               out.print("out.writeShort($result);");
842             else if (returntype == Integer.TYPE)
843               out.print("out.writeInt($result);");
844             else if (returntype == Long.TYPE)
845               out.print("out.writeLong($result);");
846             else if (returntype == Float.TYPE)
847               out.print("out.writeFloat($result);");
848             else if (returntype == Double.TYPE)
849               out.print("out.writeDouble($result);");
850             else
851               out.print("out.writeObject($result);");
852           }
853         ctrl.unindent();
854         out.println("}");
855         out.print("catch (java.io.IOException e) {");
856         ctrl.indent();
857         out.print("throw new java.rmi.MarshalException(\"error marshalling return\", e);");
858         ctrl.unindent();
859         out.println("}");
860         out.print("break;");
861
862         ctrl.unindent();
863         out.println("}");
864         out.println();
865       }
866
867     out.print("default:");
868     ctrl.indent();
869     out.print("throw new java.rmi.UnmarshalException(\"invalid method number\");");
870     ctrl.unindent();
871     out.print("}");
872
873     ctrl.unindent();
874     out.print("}");
875
876     ctrl.unindent();
877     out.println("}");
878
879     out.close();
880   }
881
882   private void compile(String name) throws Exception
883   {
884     Compiler comp = Compiler.getInstance();
885     if (verbose)
886       System.out.println("[Compiling class " + name + "]");
887     comp.setDestination(destination);
888     if (classpath != null)
889       comp.setClasspath(classpath);
890     comp.compile(name);
891   }
892
893   private static String getPrettyName(Class cls)
894   {
895     StringBuffer str = new StringBuffer();
896     for (int count = 0;; count++)
897       {
898         if (! cls.isArray())
899           {
900             str.append(cls.getName());
901             for (; count > 0; count--)
902               str.append("[]");
903             return (str.toString());
904           }
905         cls = cls.getComponentType();
906       }
907   }
908
909 /**
910  * Sort exceptions so the most general go last.
911  */
912   private Class[] sortExceptions(Class[] except)
913   {
914     for (int i = 0; i < except.length; i++)
915       {
916         for (int j = i + 1; j < except.length; j++)
917           {
918             if (except[i].isAssignableFrom(except[j]))
919               {
920                 Class tmp = except[i];
921                 except[i] = except[j];
922                 except[j] = tmp;
923               }
924           }
925       }
926     return (except);
927   }
928
929 /**
930  * Process the options until we find the first argument.
931  */
932   private void parseOptions()
933   {
934     for (;;)
935       {
936         if (next >= args.length || args[next].charAt(0) != '-')
937           break;
938         String arg = args[next];
939         next++;
940
941         // Accept `--' options if they look long enough.
942         if (arg.length() > 3 && arg.charAt(0) == '-' && arg.charAt(1) == '-')
943           arg = arg.substring(1);
944
945         if (arg.equals("-keep"))
946           keep = true;
947         else if (arg.equals("-keepgenerated"))
948           keep = true;
949         else if (arg.equals("-v1.1"))
950           {
951             need11Stubs = true;
952             need12Stubs = false;
953           }
954         else if (arg.equals("-vcompat"))
955           {
956             need11Stubs = true;
957             need12Stubs = true;
958           }
959         else if (arg.equals("-v1.2"))
960           {
961             need11Stubs = false;
962             need12Stubs = true;
963           }
964         else if (arg.equals("-g"))
965           {
966           }
967         else if (arg.equals("-depend"))
968           {
969           }
970         else if (arg.equals("-nowarn"))
971           {
972           }
973         else if (arg.equals("-verbose"))
974           verbose = true;
975         else if (arg.equals("-nocompile"))
976           compile = false;
977         else if (arg.equals("-classpath"))
978           {
979             classpath = args[next];
980             next++;
981             StringTokenizer st =
982               new StringTokenizer(classpath, File.pathSeparator);
983             URL[] u = new URL[st.countTokens()];
984             for (int i = 0; i < u.length; i++)
985               {
986                 String path = st.nextToken();
987                 File f = new File(path);
988                 try
989                   {
990                     u[i] = f.toURL();
991                   }
992                 catch (MalformedURLException mue)
993                   {
994                     error("malformed classpath component " + path);
995                   }
996               }
997             loader = new URLClassLoader(u);
998           }
999         else if (arg.equals("-help"))
1000           usage();
1001         else if (arg.equals("-version"))
1002           {
1003             System.out.println("rmic (" + System.getProperty("java.vm.name")
1004                                + ") " + System.getProperty("java.vm.version"));
1005             System.out.println();
1006             System.out.println("Copyright 2006 Free Software Foundation, Inc.");
1007             System.out.println("This is free software; see the source for copying conditions.  There is NO");
1008             System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
1009             System.exit(0);
1010           }
1011         else if (arg.equals("-d"))
1012           {
1013             destination = args[next];
1014             next++;
1015           }
1016         else if (arg.charAt(1) == 'J')
1017           {
1018           }
1019         else
1020           error("unrecognized option `" + arg + "'");
1021       }
1022   }
1023
1024   private void findRemoteMethods() {
1025     List rmeths = new ArrayList();
1026     for (Class cur = clazz; cur != null; cur = cur.getSuperclass())
1027       {
1028         Class[] interfaces = cur.getInterfaces();
1029         for (int i = 0; i < interfaces.length; i++)
1030           {
1031             if (java.rmi.Remote.class.isAssignableFrom(interfaces[i]))
1032               {
1033                 Class remoteInterface = interfaces[i];
1034                 if (verbose)
1035                   System.out.println
1036                     ("[implements " + remoteInterface.getName() + "]");
1037
1038                 // check if the methods declare RemoteExceptions
1039                 Method[] meths = remoteInterface.getMethods();
1040                 for (int j = 0; j < meths.length; j++)
1041                   {
1042                     Method m = meths[j];
1043                     Class[] exs = m.getExceptionTypes();
1044
1045                     boolean throwsRemote = false;
1046                     for (int k = 0; k < exs.length; k++)
1047                       {
1048                         if (exs[k].isAssignableFrom(RemoteException.class))
1049                           throwsRemote = true;
1050                       }
1051
1052                     if (! throwsRemote)
1053                       {
1054                         logError("Method " + m
1055                                  + " does not throw a RemoteException");
1056                         continue;
1057                       }
1058
1059                     rmeths.add(m);
1060                   }
1061
1062                 mRemoteInterfaces.add(remoteInterface);
1063               }
1064           }
1065       }
1066
1067     // intersect exceptions for doubly inherited methods
1068     boolean[] skip = new boolean[rmeths.size()];
1069     for (int i = 0; i < skip.length; i++)
1070       skip[i] = false;
1071     List methrefs = new ArrayList();
1072     for (int i = 0; i < rmeths.size(); i++)
1073       {
1074         if (skip[i]) continue;
1075         Method current = (Method) rmeths.get(i);
1076         MethodRef ref = new MethodRef(current);
1077         for (int j = i+1; j < rmeths.size(); j++)
1078           {
1079             Method other = (Method) rmeths.get(j);
1080             if (ref.isMatch(other))
1081               {
1082                 ref.intersectExceptions(other);
1083                 skip[j] = true;
1084               }
1085           }
1086         methrefs.add(ref);
1087       }
1088
1089     // Convert into a MethodRef array and sort them
1090     remotemethods = (MethodRef[])
1091       methrefs.toArray(new MethodRef[methrefs.size()]);
1092     Arrays.sort(remotemethods);
1093   }
1094
1095 /**
1096  * Prints an error to System.err and increases the error count.
1097  * @param theError
1098  */
1099   private void logError(String theError)
1100   {
1101     errorCount++;
1102     System.err.println("error:" + theError);
1103   }
1104
1105   private static void error(String message)
1106   {
1107     System.err.println("rmic: " + message);
1108     System.err.println("Try `rmic --help' for more information.");
1109     System.exit(1);
1110   }
1111
1112   private static void usage()
1113   {
1114     System.out.println("Usage: rmic [OPTION]... CLASS...\n" + "\n"
1115                        + "      -keep                   Don't delete any intermediate files\n"
1116                        + "      -keepgenerated          Same as -keep\n"
1117                        + "      -v1.1                   Java 1.1 style stubs only\n"
1118                        + "      -vcompat                Java 1.1 & Java 1.2 stubs\n"
1119                        + "      -v1.2                   Java 1.2 style stubs only\n"
1120                        + "      -g *                    Generated debugging information\n"
1121                        + "      -depend *               Recompile out-of-date files\n"
1122                        + "      -nowarn *               Suppress warning messages\n"
1123                        + "      -nocompile              Don't compile the generated files\n"
1124                        + "      -verbose                Output what's going on\n"
1125                        + "      -classpath <path> *     Use given path as classpath\n"
1126                        + "      -d <directory>          Specify where to place generated classes\n"
1127                        + "      -J<flag> *              Pass flag to Java\n"
1128                        + "      -help                   Print this help, then exit\n"
1129                        + "      -version                Print version number, then exit\n" + "\n"
1130                        + "  * Option currently ignored\n"
1131                        + "Long options can be used with `--option' form as well.");
1132     System.exit(0);
1133   }
1134
1135   private static class MethodRef
1136     implements Comparable
1137   {
1138     Method meth;
1139     long hash;
1140     List exceptions;
1141     private String sig;
1142
1143     MethodRef(Method m)
1144     {
1145       meth = m;
1146       sig = m.getName(); // XXX should be full signature used to compute hash
1147       hash = RMIHashes.getMethodHash(m);
1148       // add exceptions removing subclasses
1149       exceptions = removeSubclasses(m.getExceptionTypes());
1150     }
1151
1152     public int compareTo(Object obj)
1153     {
1154       MethodRef that = (MethodRef) obj;
1155       int name = this.meth.getName().compareTo(that.meth.getName());
1156       if (name == 0) {
1157         return this.sig.compareTo(that.sig);
1158       }
1159       return name;
1160     }
1161
1162     public boolean isMatch(Method m)
1163     {
1164       if (!meth.getName().equals(m.getName()))
1165         return false;
1166
1167       Class[] params1 = meth.getParameterTypes();
1168       Class[] params2 = m.getParameterTypes();
1169       if (params1.length != params2.length)
1170         return false;
1171
1172       for (int i = 0; i < params1.length; i++)
1173         if (!params1[i].equals(params2[i])) return false;
1174
1175       return true;
1176     }
1177
1178     private static List removeSubclasses(Class[] classes)
1179     {
1180       List list = new ArrayList();
1181       for (int i = 0; i < classes.length; i++)
1182         {
1183           Class candidate = classes[i];
1184           boolean add = true;
1185           for (int j = 0; j < classes.length; j++)
1186             {
1187               if (classes[j].equals(candidate))
1188                 continue;
1189               else if (classes[j].isAssignableFrom(candidate))
1190                 add = false;
1191             }
1192           if (add) list.add(candidate);
1193         }
1194
1195       return list;
1196     }
1197
1198     public void intersectExceptions(Method m)
1199     {
1200       List incoming = removeSubclasses(m.getExceptionTypes());
1201
1202       List updated = new ArrayList();
1203
1204       for (int i = 0; i < exceptions.size(); i++)
1205         {
1206           Class outer = (Class) exceptions.get(i);
1207           boolean addOuter = false;
1208           for (int j = 0; j < incoming.size(); j++)
1209             {
1210               Class inner = (Class) incoming.get(j);
1211
1212               if (inner.equals(outer) || inner.isAssignableFrom(outer))
1213                 addOuter = true;
1214               else if (outer.isAssignableFrom(inner))
1215                 updated.add(inner);
1216             }
1217
1218           if (addOuter)
1219             updated.add(outer);
1220         }
1221
1222       exceptions = updated;
1223     }
1224   }
1225 }