Source for gnu.java.rmi.rmic.RMIC

   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: }