44 import sun.tools.java.ClassDefinition;
45 import sun.tools.java.ClassDeclaration;
46 import sun.tools.java.ClassNotFound;
47 import sun.tools.java.ClassFile;
48 import sun.tools.java.MemberDefinition;
49 import com.sun.corba.se.impl.util.Utility;
50
51 /**
52 * A Generator object will generate the Java source code of the stub
53 * and skeleton classes for an RMI remote implementation class, using
54 * a particular stub protocol version.
55 *
56 * WARNING: The contents of this source file are not part of any
57 * supported API. Code that depends on them does so at its own risk:
58 * they are subject to change or removal without notice.
59 *
60 * @author Peter Jones, Bryan Atsatt
61 */
62 public class RMIGenerator implements RMIConstants, Generator {
63
64 private static final Hashtable versionOptions = new Hashtable();
65 static {
66 versionOptions.put("-v1.1", new Integer(STUB_VERSION_1_1));
67 versionOptions.put("-vcompat", new Integer(STUB_VERSION_FAT));
68 versionOptions.put("-v1.2", new Integer(STUB_VERSION_1_2));
69 }
70
71 /**
72 * Default constructor for Main to use.
73 */
74 public RMIGenerator() {
75 version = STUB_VERSION_1_2; // default is -v1.2 (see 4638155)
76 }
77
78 /**
79 * Examine and consume command line arguments.
80 * @param argv The command line arguments. Ignore null
81 * and unknown arguments. Set each consumed argument to null.
82 * @param error Report any errors using the main.error() methods.
83 * @return true if no errors, false otherwise.
84 */
85 public boolean parseArgs(String argv[], Main main) {
86 String explicitVersion = null;
87 for (int i = 0; i < argv.length; i++) {
88 if (argv[i] != null) {
89 String arg = argv[i].toLowerCase();
90 if (versionOptions.containsKey(arg)) {
91 if (explicitVersion != null &&
92 !explicitVersion.equals(arg))
93 {
94 main.error("rmic.cannot.use.both",
95 explicitVersion, arg);
96 return false;
97 }
98 explicitVersion = arg;
99 version = ((Integer) versionOptions.get(arg)).intValue();
100 argv[i] = null;
101 }
102 }
103 }
104 return true;
105 }
106
107 /**
108 * Generate the source files for the stub and/or skeleton classes
109 * needed by RMI for the given remote implementation class.
110 *
111 * @param env compiler environment
112 * @param cdef definition of remote implementation class
113 * to generate stubs and/or skeletons for
114 * @param destDir directory for the root of the package hierarchy
115 * for generated files
116 */
117 public void generate(BatchEnvironment env, ClassDefinition cdef, File destDir) {
118 RemoteClass remoteClass = RemoteClass.forClass(env, cdef);
119 if (remoteClass == null) // exit if an error occurred
502 }
503 p.pOlnI("{");
504
505 /*
506 * The RemoteRef.invoke methods throw Exception, but unless this
507 * stub method throws Exception as well, we must catch Exceptions
508 * thrown from the invocation. So we must catch Exception and
509 * rethrow something we can throw: UnexpectedException, which is a
510 * subclass of RemoteException. But for any subclasses of Exception
511 * that we can throw, like RemoteException, RuntimeException, and
512 * any of the exceptions declared by this stub method, we want them
513 * to pass through unharmed, so first we must catch any such
514 * exceptions and rethrow it directly.
515 *
516 * We have to be careful generating the rethrowing catch blocks
517 * here, because javac will flag an error if there are any
518 * unreachable catch blocks, i.e. if the catch of an exception class
519 * follows a previous catch of it or of one of its superclasses.
520 * The following method invocation takes care of these details.
521 */
522 Vector catchList = computeUniqueCatchList(exceptions);
523
524 /*
525 * If we need to catch any particular exceptions (i.e. this method
526 * does not declare java.lang.Exception), put the entire stub
527 * method in a try block.
528 */
529 if (catchList.size() > 0) {
530 p.plnI("try {");
531 }
532
533 if (version == STUB_VERSION_FAT) {
534 p.plnI("if (useNewInvoke) {");
535 }
536 if (version == STUB_VERSION_FAT ||
537 version == STUB_VERSION_1_2)
538 {
539 if (!returnType.isType(TC_VOID)) {
540 p.p("Object $result = "); // REMIND: why $?
541 }
542 p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
598 p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
599 p.pln("throw new " + idUnmarshalException +
600 "(\"error unmarshalling return\", e);");
601 }
602 p.pOlnI("} finally {");
603 p.pln("ref.done(call);");
604 p.pOln("}");
605 p.pln("return $result;");
606 }
607 }
608 if (version == STUB_VERSION_FAT) {
609 p.pOln("}"); // end if/else (useNewInvoke) block
610 }
611
612 /*
613 * If we need to catch any particular exceptions, finally write
614 * the catch blocks for them, rethrow any other Exceptions with an
615 * UnexpectedException, and end the try block.
616 */
617 if (catchList.size() > 0) {
618 for (Enumeration enumeration = catchList.elements();
619 enumeration.hasMoreElements();)
620 {
621 ClassDefinition def = (ClassDefinition) enumeration.nextElement();
622 p.pOlnI("} catch (" + def.getName() + " e) {");
623 p.pln("throw e;");
624 }
625 p.pOlnI("} catch (java.lang.Exception e) {");
626 p.pln("throw new " + idUnexpectedException +
627 "(\"undeclared checked exception\", e);");
628 p.pOln("}"); // end try/catch block
629 }
630
631 p.pOln("}"); // end stub method
632 }
633
634 /**
635 * Compute the exceptions which need to be caught and rethrown in a
636 * stub method before wrapping Exceptions in UnexpectedExceptions,
637 * given the exceptions declared in the throws clause of the method.
638 * Returns a Vector containing ClassDefinition objects for each
639 * exception to catch. Each exception is guaranteed to be unique,
640 * i.e. not a subclass of any of the other exceptions in the Vector,
641 * so the catch blocks for these exceptions may be generated in any
642 * order relative to each other.
643 *
644 * RemoteException and RuntimeException are each automatically placed
645 * in the returned Vector (if none of their superclasses are already
646 * present), since those exceptions should always be directly rethrown
647 * by a stub method.
648 *
649 * The returned Vector will be empty if java.lang.Exception or one
650 * of its superclasses is in the throws clause of the method, indicating
651 * that no exceptions need to be caught.
652 */
653 private Vector computeUniqueCatchList(ClassDeclaration[] exceptions) {
654 Vector uniqueList = new Vector(); // unique exceptions to catch
655
656 uniqueList.addElement(defRuntimeException);
657 uniqueList.addElement(defRemoteException);
658
659 /* For each exception declared by the stub method's throws clause: */
660 nextException:
661 for (int i = 0; i < exceptions.length; i++) {
662 ClassDeclaration decl = exceptions[i];
663 try {
664 if (defException.subClassOf(env, decl)) {
665 /*
666 * (If java.lang.Exception (or a superclass) was declared
667 * in the throws clause of this stub method, then we don't
668 * have to bother catching anything; clear the list and
669 * return.)
670 */
671 uniqueList.clear();
672 break;
673 } else if (!defException.superClassOf(env, decl)) {
674 /*
675 * Ignore other Throwables that do not extend Exception,
676 * since they do not need to be caught anyway.
677 */
678 continue;
679 }
680 /*
681 * Compare this exception against the current list of
682 * exceptions that need to be caught:
683 */
684 for (int j = 0; j < uniqueList.size();) {
685 ClassDefinition def =
686 (ClassDefinition) uniqueList.elementAt(j);
687 if (def.superClassOf(env, decl)) {
688 /*
689 * If a superclass of this exception is already on
690 * the list to catch, then ignore and continue;
691 */
692 continue nextException;
693 } else if (def.subClassOf(env, decl)) {
694 /*
695 * If a subclass of this exception is on the list
696 * to catch, then remove it.
697 */
698 uniqueList.removeElementAt(j);
699 } else {
700 j++; // else continue comparing
701 }
702 }
703 /* This exception is unique: add it to the list to catch. */
704 uniqueList.addElement(decl.getClassDefinition(env));
705 } catch (ClassNotFound e) {
706 env.error(0, "class.not.found", e.name, decl.getName());
|
44 import sun.tools.java.ClassDefinition;
45 import sun.tools.java.ClassDeclaration;
46 import sun.tools.java.ClassNotFound;
47 import sun.tools.java.ClassFile;
48 import sun.tools.java.MemberDefinition;
49 import com.sun.corba.se.impl.util.Utility;
50
51 /**
52 * A Generator object will generate the Java source code of the stub
53 * and skeleton classes for an RMI remote implementation class, using
54 * a particular stub protocol version.
55 *
56 * WARNING: The contents of this source file are not part of any
57 * supported API. Code that depends on them does so at its own risk:
58 * they are subject to change or removal without notice.
59 *
60 * @author Peter Jones, Bryan Atsatt
61 */
62 public class RMIGenerator implements RMIConstants, Generator {
63
64 private static final Hashtable<String, Integer> versionOptions = new Hashtable<>();
65 static {
66 versionOptions.put("-v1.1", new Integer(STUB_VERSION_1_1));
67 versionOptions.put("-vcompat", new Integer(STUB_VERSION_FAT));
68 versionOptions.put("-v1.2", new Integer(STUB_VERSION_1_2));
69 }
70
71 /**
72 * Default constructor for Main to use.
73 */
74 public RMIGenerator() {
75 version = STUB_VERSION_1_2; // default is -v1.2 (see 4638155)
76 }
77
78 /**
79 * Examine and consume command line arguments.
80 * @param argv The command line arguments. Ignore null
81 * and unknown arguments. Set each consumed argument to null.
82 * @param error Report any errors using the main.error() methods.
83 * @return true if no errors, false otherwise.
84 */
85 public boolean parseArgs(String argv[], Main main) {
86 String explicitVersion = null;
87 for (int i = 0; i < argv.length; i++) {
88 if (argv[i] != null) {
89 String arg = argv[i].toLowerCase();
90 if (versionOptions.containsKey(arg)) {
91 if (explicitVersion != null &&
92 !explicitVersion.equals(arg))
93 {
94 main.error("rmic.cannot.use.both",
95 explicitVersion, arg);
96 return false;
97 }
98 explicitVersion = arg;
99 version = versionOptions.get(arg);
100 argv[i] = null;
101 }
102 }
103 }
104 return true;
105 }
106
107 /**
108 * Generate the source files for the stub and/or skeleton classes
109 * needed by RMI for the given remote implementation class.
110 *
111 * @param env compiler environment
112 * @param cdef definition of remote implementation class
113 * to generate stubs and/or skeletons for
114 * @param destDir directory for the root of the package hierarchy
115 * for generated files
116 */
117 public void generate(BatchEnvironment env, ClassDefinition cdef, File destDir) {
118 RemoteClass remoteClass = RemoteClass.forClass(env, cdef);
119 if (remoteClass == null) // exit if an error occurred
502 }
503 p.pOlnI("{");
504
505 /*
506 * The RemoteRef.invoke methods throw Exception, but unless this
507 * stub method throws Exception as well, we must catch Exceptions
508 * thrown from the invocation. So we must catch Exception and
509 * rethrow something we can throw: UnexpectedException, which is a
510 * subclass of RemoteException. But for any subclasses of Exception
511 * that we can throw, like RemoteException, RuntimeException, and
512 * any of the exceptions declared by this stub method, we want them
513 * to pass through unharmed, so first we must catch any such
514 * exceptions and rethrow it directly.
515 *
516 * We have to be careful generating the rethrowing catch blocks
517 * here, because javac will flag an error if there are any
518 * unreachable catch blocks, i.e. if the catch of an exception class
519 * follows a previous catch of it or of one of its superclasses.
520 * The following method invocation takes care of these details.
521 */
522 Vector<ClassDefinition> catchList = computeUniqueCatchList(exceptions);
523
524 /*
525 * If we need to catch any particular exceptions (i.e. this method
526 * does not declare java.lang.Exception), put the entire stub
527 * method in a try block.
528 */
529 if (catchList.size() > 0) {
530 p.plnI("try {");
531 }
532
533 if (version == STUB_VERSION_FAT) {
534 p.plnI("if (useNewInvoke) {");
535 }
536 if (version == STUB_VERSION_FAT ||
537 version == STUB_VERSION_1_2)
538 {
539 if (!returnType.isType(TC_VOID)) {
540 p.p("Object $result = "); // REMIND: why $?
541 }
542 p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
598 p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
599 p.pln("throw new " + idUnmarshalException +
600 "(\"error unmarshalling return\", e);");
601 }
602 p.pOlnI("} finally {");
603 p.pln("ref.done(call);");
604 p.pOln("}");
605 p.pln("return $result;");
606 }
607 }
608 if (version == STUB_VERSION_FAT) {
609 p.pOln("}"); // end if/else (useNewInvoke) block
610 }
611
612 /*
613 * If we need to catch any particular exceptions, finally write
614 * the catch blocks for them, rethrow any other Exceptions with an
615 * UnexpectedException, and end the try block.
616 */
617 if (catchList.size() > 0) {
618 for (Enumeration<ClassDefinition> enumeration = catchList.elements();
619 enumeration.hasMoreElements();)
620 {
621 ClassDefinition def = enumeration.nextElement();
622 p.pOlnI("} catch (" + def.getName() + " e) {");
623 p.pln("throw e;");
624 }
625 p.pOlnI("} catch (java.lang.Exception e) {");
626 p.pln("throw new " + idUnexpectedException +
627 "(\"undeclared checked exception\", e);");
628 p.pOln("}"); // end try/catch block
629 }
630
631 p.pOln("}"); // end stub method
632 }
633
634 /**
635 * Compute the exceptions which need to be caught and rethrown in a
636 * stub method before wrapping Exceptions in UnexpectedExceptions,
637 * given the exceptions declared in the throws clause of the method.
638 * Returns a Vector containing ClassDefinition objects for each
639 * exception to catch. Each exception is guaranteed to be unique,
640 * i.e. not a subclass of any of the other exceptions in the Vector,
641 * so the catch blocks for these exceptions may be generated in any
642 * order relative to each other.
643 *
644 * RemoteException and RuntimeException are each automatically placed
645 * in the returned Vector (if none of their superclasses are already
646 * present), since those exceptions should always be directly rethrown
647 * by a stub method.
648 *
649 * The returned Vector will be empty if java.lang.Exception or one
650 * of its superclasses is in the throws clause of the method, indicating
651 * that no exceptions need to be caught.
652 */
653 private Vector<ClassDefinition> computeUniqueCatchList(ClassDeclaration[] exceptions) {
654 Vector<ClassDefinition> uniqueList = new Vector<>(); // unique exceptions to catch
655
656 uniqueList.addElement(defRuntimeException);
657 uniqueList.addElement(defRemoteException);
658
659 /* For each exception declared by the stub method's throws clause: */
660 nextException:
661 for (int i = 0; i < exceptions.length; i++) {
662 ClassDeclaration decl = exceptions[i];
663 try {
664 if (defException.subClassOf(env, decl)) {
665 /*
666 * (If java.lang.Exception (or a superclass) was declared
667 * in the throws clause of this stub method, then we don't
668 * have to bother catching anything; clear the list and
669 * return.)
670 */
671 uniqueList.clear();
672 break;
673 } else if (!defException.superClassOf(env, decl)) {
674 /*
675 * Ignore other Throwables that do not extend Exception,
676 * since they do not need to be caught anyway.
677 */
678 continue;
679 }
680 /*
681 * Compare this exception against the current list of
682 * exceptions that need to be caught:
683 */
684 for (int j = 0; j < uniqueList.size();) {
685 ClassDefinition def =
686 uniqueList.elementAt(j);
687 if (def.superClassOf(env, decl)) {
688 /*
689 * If a superclass of this exception is already on
690 * the list to catch, then ignore and continue;
691 */
692 continue nextException;
693 } else if (def.subClassOf(env, decl)) {
694 /*
695 * If a subclass of this exception is on the list
696 * to catch, then remove it.
697 */
698 uniqueList.removeElementAt(j);
699 } else {
700 j++; // else continue comparing
701 }
702 }
703 /* This exception is unique: add it to the list to catch. */
704 uniqueList.addElement(decl.getClassDefinition(env));
705 } catch (ClassNotFound e) {
706 env.error(0, "class.not.found", e.name, decl.getName());
|