You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MainWrapper.java 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.internal.tools.ant.taskdefs;
  14. import java.io.File;
  15. import java.io.PrintStream;
  16. import java.lang.reflect.InvocationTargetException;
  17. import java.lang.reflect.Method;
  18. import java.lang.reflect.Modifier;
  19. import org.aspectj.testing.util.LangUtil;
  20. /**
  21. * Wrapper to invoke class identified by setting VM argument.
  22. * Caller must set a system property "MainWrapper.classname"
  23. * to the fully-qualified name of the target class to invoke,
  24. * and the target class must be resolvable from the defining
  25. * class loader of this class.
  26. * VM argument name is available as <code>PROP_NAME</code>, but
  27. * is set by adding the following to the command line:
  28. * <code>-DMainWrapper.classname="fully.qualified.Classname"</code>.
  29. * This returns -1 if unable to load the main method,
  30. * 1 if the invoked method throws an exception, and 0 otherwise.
  31. */
  32. public class MainWrapper {
  33. /** MUST set the fully-qualified name of class to invoke using
  34. * a VM property of this name
  35. * tracked in Ajctest.java */
  36. public static final String PROP_NAME = "MainWrapper.classname";
  37. /** May set the path to a classes diretory,
  38. * to interpret class names and load classes.
  39. * Tracked in Ajctest.java */
  40. public static final String CLASSDIR_NAME = "MainWrapper.classdir";
  41. /** to disable returning int via System.exit, set to boolean true value (todo: ignored) */
  42. public static final String SIGNAL_EXCEPTION_NAME = "MainWrapper.signalException";
  43. /** to disable returning via System.exit on first Throwable, set to boolean true value (todo: ignored) */
  44. public static final String FAIL_ON_EXCEPTION_NAME = "MainWrapper.failOnException";
  45. /** quit on first exception */ // todo public class controls - yuck
  46. public static boolean FAIL_ON_EXCEPTION = true;
  47. /** signal number of exceptions with int return value */
  48. public static boolean SIGNAL_EXCEPTION = true;
  49. /** redirect messages for exceptions; if null, none printed */
  50. public static PrintStream OUT_STREAM = System.err;
  51. /** result accumulated, possibly from multiple threads */
  52. private static int result;
  53. /**
  54. * Run target class's main(args), doing a System.exit() with
  55. * a value > 0 for the number of Throwable that
  56. * the target class threw that
  57. * makes it through to a top-level ThreadGroup. (This is
  58. * strictly speaking not correct since applications can live
  59. * after their exceptions stop a thread.)
  60. * Exit with a value < 0 if there were exceptions in loading
  61. * the target class. Messages are printed to OUT_STREAM.
  62. */
  63. public static void main(String[] args) {
  64. String classname = "no property : " + PROP_NAME;
  65. Method main = null;
  66. // setup: this try block is for loading main method - return -1 if fail
  67. try {
  68. // access classname from jvm arg
  69. classname = System.getProperty(PROP_NAME);
  70. // this will fail if the class is not available from this classloader
  71. Class<?> cl = Class.forName(classname);
  72. final Class<?>[] argTypes = new Class[] {String[].class};
  73. // will fail if no main method
  74. main = cl.getMethod("main", argTypes);
  75. if (!Modifier.isStatic(main.getModifiers())) {
  76. PrintStream outStream = OUT_STREAM;
  77. if (null != outStream) outStream.println("main is not static");
  78. result = -1;
  79. }
  80. // if user also request loading of all classes...
  81. String classesDir = System.getProperty(CLASSDIR_NAME);
  82. if ((null != classesDir) && (0 < classesDir.length())) {
  83. MainWrapper.loadAllClasses(new File(classesDir));
  84. }
  85. } catch (Throwable t) {
  86. if (1 != result) result--;
  87. reportException("setup Throwable invoking class " + classname, t);
  88. }
  89. // run: this try block is for running things - get Throwable from our thread here
  90. if ((null != main) && (0 == result)) {
  91. try {
  92. runInOurThreadGroup(main, args);
  93. } catch (Throwable t) {
  94. if (result > -1) {
  95. result++;
  96. }
  97. reportException("run Throwable invoking class " + classname, t);
  98. }
  99. }
  100. if ((0 != result) && (SIGNAL_EXCEPTION)) {
  101. System.exit(result);
  102. }
  103. }
  104. static void runInOurThreadGroup(final Method main, final String[] args) {
  105. final String classname = main.getDeclaringClass().getName();
  106. ThreadGroup ourGroup = new ThreadGroup("MainWrapper ThreadGroup") {
  107. public void uncaughtException(Thread t, Throwable e) {
  108. reportException("uncaughtException invoking " + classname, e);
  109. result++;
  110. if (FAIL_ON_EXCEPTION) {
  111. System.exit((SIGNAL_EXCEPTION ? result : 0));
  112. }
  113. }
  114. };
  115. Runnable runner = new Runnable() {
  116. public void run() {
  117. try {
  118. main.invoke(null, new Object[] {args});
  119. } catch (InvocationTargetException e) {
  120. result = -1;
  121. reportException("InvocationTargetException invoking " + classname, e);
  122. } catch (IllegalAccessException e) {
  123. result = -1;
  124. reportException("IllegalAccessException invoking " + classname, e);
  125. }
  126. }
  127. };
  128. Thread newMain = new Thread(ourGroup, runner, "pseudo-main");
  129. newMain.start();
  130. try {
  131. newMain.join();
  132. } catch (InterruptedException e) {
  133. result = -1; // todo: InterruptedException might be benign - retry?
  134. reportException("Interrupted while waiting for to join " + newMain, e);
  135. }
  136. }
  137. /**
  138. * Try to load all classes in a directory.
  139. * @throws Error if any failed
  140. */
  141. static protected void loadAllClasses(File classesDir) {
  142. if (null != classesDir) {
  143. String[] names = LangUtil.classesIn(classesDir);
  144. StringBuffer err = new StringBuffer();
  145. LangUtil.loadClasses(names, null, err);
  146. if (0 < err.length()) {
  147. throw new Error("MainWrapper Errors loading classes: "
  148. + err.toString());
  149. }
  150. }
  151. }
  152. static void reportException(String context, Throwable t) {
  153. PrintStream outStream = OUT_STREAM;
  154. if (null != outStream) {
  155. while ((null != t) &&
  156. (InvocationTargetException.class.isAssignableFrom(t.getClass()))) {
  157. t = ((InvocationTargetException) t).getTargetException();
  158. }
  159. outStream.println(" context: " + context);
  160. outStream.println(" message: " + t.getMessage());
  161. t.printStackTrace(outStream);
  162. }
  163. }
  164. } // MainWrapper