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.

JavaRun.java 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Xerox/PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.testing.harness.bridge;
  13. import java.io.ByteArrayOutputStream;
  14. import java.io.File;
  15. import java.io.FileDescriptor;
  16. import java.io.PrintStream;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.net.InetAddress;
  20. import java.net.URL;
  21. import java.security.Permission;
  22. import java.util.ArrayList;
  23. import java.util.Arrays;
  24. import org.aspectj.bridge.AbortException;
  25. import org.aspectj.bridge.IMessageHandler;
  26. import org.aspectj.bridge.MessageUtil;
  27. import org.aspectj.testing.Tester;
  28. import org.aspectj.testing.run.IRunIterator;
  29. import org.aspectj.testing.run.IRunStatus;
  30. import org.aspectj.testing.run.WrappedRunIterator;
  31. import org.aspectj.testing.util.TestClassLoader;
  32. import org.aspectj.testing.util.TestUtil;
  33. import org.aspectj.testing.xml.SoftMessage;
  34. import org.aspectj.testing.xml.XMLWriter;
  35. import org.aspectj.util.FileUtil;
  36. import org.aspectj.util.LangUtil;
  37. import org.aspectj.weaver.loadtime.WeavingURLClassLoader;
  38. /**
  39. * Run a class in this VM using reflection.
  40. * Forked mode supported, but through system properties:
  41. * - javarun.fork: anything to enable forking
  42. * - javarun.java: path to java executable (optional)
  43. * - javarun.java.home: JAVA_HOME for java (optional)
  44. * (normally requires javarun.java)
  45. * - javarun.classpath: a prefix to the run classpath (optional)
  46. */
  47. public class JavaRun implements IAjcRun {
  48. private static void appendClasspath(StringBuffer cp, Object[] entries) {
  49. if (!LangUtil.isEmpty(entries)) {
  50. for (int i = 0; i < entries.length; i++) {
  51. Object entry = entries[i];
  52. if (entry instanceof String) {
  53. cp.append((String) entry);
  54. cp.append(File.pathSeparator);
  55. } else if (entry instanceof File) {
  56. String s = FileUtil.getBestPath((File) entry);
  57. if (null != s) {
  58. cp.append(s);
  59. cp.append(File.pathSeparator);
  60. }
  61. }
  62. }
  63. }
  64. }
  65. Spec spec;
  66. private Sandbox sandbox;
  67. /** programmatic initialization per spec */
  68. public JavaRun(Spec spec) {
  69. this.spec = spec;
  70. }
  71. // XXX init(Spec)
  72. /**
  73. * This checks the spec for a class name
  74. * and checks the sandbox for a readable test source directory,
  75. * a writable run dir, and (non-null, possibly-empty) lists
  76. * of readable classpath dirs and jars,
  77. * and, if fork is enabled, that java can be read.
  78. * @return true if all checks pass
  79. * @see org.aspectj.testing.harness.bridge.AjcTest.IAjcRun#setup(File, File)
  80. */
  81. public boolean setupAjcRun(Sandbox sandbox, Validator validator) {
  82. this.sandbox = sandbox;
  83. sandbox.javaRunInit(this);
  84. return (validator.nullcheck(spec.className, "class name")
  85. && validator.nullcheck(sandbox, "sandbox")
  86. && validator.canReadDir(sandbox.getTestBaseSrcDir(this), "testBaseSrc dir")
  87. && validator.canWriteDir(sandbox.runDir, "run dir")
  88. && validator.canReadFiles(sandbox.getClasspathJars(true, this), "classpath jars")
  89. && validator.canReadDirs(sandbox.getClasspathDirectories(true, this, true), "classpath dirs")
  90. && (!spec.forkSpec.fork
  91. || validator.canRead(spec.forkSpec.java, "java"))
  92. );
  93. }
  94. /** caller must record any exceptions */
  95. public boolean run(IRunStatus status)
  96. throws IllegalAccessException,
  97. InvocationTargetException,
  98. ClassNotFoundException,
  99. NoSuchMethodException {
  100. boolean completedNormally = false;
  101. boolean passed = false;
  102. if (!LangUtil.isEmpty(spec.dirChanges)) {
  103. MessageUtil.info(status, "XXX dirChanges not implemented in JavaRun");
  104. }
  105. try {
  106. final boolean readable = true;
  107. File[] libs = sandbox.getClasspathJars(readable, this);
  108. boolean includeClassesDir = true;
  109. File[] dirs = sandbox.getClasspathDirectories(readable, this, includeClassesDir);
  110. completedNormally = (spec.forkSpec.fork)
  111. ? runInOtherVM(status, libs, dirs)
  112. : runInSameVM(status, libs, dirs);
  113. passed = completedNormally;
  114. } finally {
  115. if (!passed || !status.runResult()) {
  116. MessageUtil.info(status, spec.toLongString());
  117. MessageUtil.info(status, "sandbox: " + sandbox);
  118. }
  119. }
  120. return passed;
  121. }
  122. protected boolean runInSameVM(IRunStatus status, File[] libs, File[] dirs) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  123. ClassLoader loader = null;
  124. boolean completedNormally = false;
  125. boolean passed = false;
  126. ByteArrayOutputStream outSnoop = null;
  127. PrintStream oldOut = null;
  128. ByteArrayOutputStream errSnoop = null;
  129. PrintStream oldErr = null;
  130. if (spec.outStreamIsError) {
  131. outSnoop = new ByteArrayOutputStream();
  132. oldOut = System.out;
  133. System.setOut(new PrintStream(outSnoop, true));
  134. }
  135. if (spec.errStreamIsError) {
  136. errSnoop = new ByteArrayOutputStream();
  137. oldErr = System.err;
  138. System.setErr(new PrintStream(errSnoop, true));
  139. }
  140. Class targetClass = null;
  141. try {
  142. final URL[] clAndLibs;
  143. {
  144. File[] files = sandbox.findFiles(spec.classpath);
  145. URL[] clURLs = FileUtil.getFileURLs(files);
  146. URL[] libURLs = FileUtil.getFileURLs(libs);
  147. clAndLibs = new URL[clURLs.length + libURLs.length];
  148. System.arraycopy(clURLs, 0, clAndLibs , 0, clURLs.length);
  149. System.arraycopy(libURLs, 0, clAndLibs, clURLs.length, libURLs.length);
  150. }
  151. if (!spec.isLTW()) {
  152. loader = new TestClassLoader(clAndLibs, dirs);
  153. } else {
  154. final URL[] aspectURLs;
  155. {
  156. File[] files = sandbox.findFiles(spec.aspectpath);
  157. aspectURLs = FileUtil.getFileURLs(files);
  158. }
  159. ArrayList classpath = new ArrayList();
  160. classpath.addAll(Arrays.asList(aspectURLs));
  161. final URL[] classURLs;
  162. {
  163. classpath.addAll(Arrays.asList(clAndLibs));
  164. URL[] urls = FileUtil.getFileURLs(dirs);
  165. classpath.addAll(Arrays.asList(urls));
  166. classpath.add(FileUtil.getFileURL(Globals.F_aspectjrt_jar));
  167. classpath.add(FileUtil.getFileURL(Globals.F_testingclient_jar));
  168. classURLs = (URL[]) classpath.toArray(new URL[0]);
  169. }
  170. ClassLoader parent = JavaRun.class.getClassLoader();
  171. loader = new WeavingURLClassLoader(classURLs, aspectURLs, parent);
  172. }
  173. // make the following load test optional
  174. // Class testAspect = loader.loadClass("org.aspectj.lang.JoinPoint");
  175. targetClass = loader.loadClass(spec.className);
  176. Method main = targetClass.getMethod("main", Globals.MAIN_PARM_TYPES);
  177. setupTester(sandbox.getTestBaseSrcDir(this), loader, status);
  178. RunSecurityManager.ME.setJavaRunThread(this);
  179. main.invoke(null, new Object[] { spec.getOptionsArray() });
  180. completedNormally = true;
  181. boolean snoopFailure =
  182. ((null != errSnoop) && 0 < errSnoop.size())
  183. || ((null != outSnoop) && 0 < outSnoop.size());
  184. passed = !snoopFailure && (null == spec.expectedException);
  185. } catch (AbortException e) {
  186. if (expectedException(e)) {
  187. passed = true;
  188. } else {
  189. throw e;
  190. }
  191. } catch (InvocationTargetException e) {
  192. // this and following clauses catch ExitCalledException
  193. Throwable thrown = LangUtil.unwrapException(e);
  194. if (null == thrown) {
  195. throw e;
  196. }
  197. if (thrown instanceof RunSecurityManager.ExitCalledException) {
  198. int i = ((RunSecurityManager.ExitCalledException) thrown).exitCode;
  199. status.finish(new Integer(i));
  200. } else if (thrown instanceof RunSecurityManager.AwtUsedException) {
  201. MessageUtil.fail(status, "test code should not use the AWT event queue");
  202. throw (RunSecurityManager.AwtUsedException) thrown;
  203. // same as: status.thrown(thrown);
  204. } else if (expectedException(thrown)) {
  205. passed = true;
  206. } else if (thrown instanceof RuntimeException) {
  207. throw (RuntimeException) thrown;
  208. } else if (thrown instanceof Error) {
  209. throw (Error) thrown;
  210. } else {
  211. throw e;
  212. }
  213. } catch (RunSecurityManager.ExitCalledException e) {
  214. // XXX need to update run validator (a) to accept null result or (b) to require zero result, and set 0 if completed normally
  215. status.finish(new Integer(e.exitCode));
  216. } catch (ClassNotFoundException e) {
  217. String[] classes = FileUtil.listFiles(sandbox.classesDir);
  218. MessageUtil.info(status, "sandbox.classes: " + Arrays.asList(classes));
  219. MessageUtil.fail(status, null, e);
  220. } finally {
  221. if (null != oldOut) {
  222. System.setOut(oldOut);
  223. }
  224. if (null != oldErr) {
  225. System.setErr(oldErr);
  226. }
  227. RunSecurityManager.ME.releaseJavaRunThread(this);
  228. if (!completedNormally) {
  229. MessageUtil.info(status, "targetClass: " + targetClass);
  230. MessageUtil.info(status, "loader: " + loader);
  231. }
  232. }
  233. return passed;
  234. }
  235. /**
  236. * Run in another VM by grabbing Java, bootclasspath, classpath, etc.
  237. * This assumes any exception or output to System.err is a failure,
  238. * and any normal completion is a pass.
  239. * @param status
  240. * @param libs
  241. * @param dirs
  242. * @return
  243. */
  244. protected boolean runInOtherVM(IRunStatus status, File[] libs, File[] dirs) {
  245. // assert spec.fork || !LangUtil.isEmpty(spec.aspectpath);
  246. ArrayList cmd = new ArrayList();
  247. cmd.add(FileUtil.getBestPath(spec.forkSpec.java));
  248. if (!LangUtil.isEmpty(spec.forkSpec.vmargs)) {
  249. cmd.addAll(Arrays.asList(spec.forkSpec.vmargs));
  250. }
  251. final String classpath;
  252. {
  253. StringBuffer cp = new StringBuffer();
  254. appendClasspath(cp, spec.forkSpec.bootclasspath);
  255. appendClasspath(cp, dirs);
  256. appendClasspath(cp, libs);
  257. File[] classpathFiles = sandbox.findFiles(spec.classpath);
  258. int cpLength = (null == classpathFiles ? 0 : classpathFiles.length);
  259. int spLength = (null == spec.classpath ? 0 : spec.classpath.length);
  260. if (cpLength != spLength) {
  261. throw new Error("unable to find " + Arrays.asList(spec.classpath)
  262. + " got " + Arrays.asList(classpathFiles));
  263. }
  264. appendClasspath(cp, classpathFiles);
  265. File[] stdlibs = {Globals.F_aspectjrt_jar, Globals.F_testingclient_jar};
  266. appendClasspath(cp, stdlibs);
  267. classpath = cp.toString();
  268. }
  269. if (!spec.isLTW()) {
  270. cmd.add("-classpath");
  271. cmd.add(classpath);
  272. } else {
  273. // verify 1.4 or above, assuming same vm as running this
  274. if (!Globals.supportsJava("1.4")) {
  275. throw new Error("load-time weaving test requires Java 1.4+");
  276. }
  277. cmd.add("-Djava.system.class.loader=org.aspectj.weaver.WeavingURLClassLoader");
  278. // assume harness VM classpath has WeavingURLClassLoader (but not others)
  279. cmd.add("-classpath");
  280. cmd.add(System.getProperty("java.class.path"));
  281. File[] aspectJars = sandbox.findFiles(spec.aspectpath);
  282. if (aspectJars.length != spec.aspectpath.length) {
  283. throw new Error("unable to find " + Arrays.asList(spec.aspectpath));
  284. }
  285. StringBuffer cp = new StringBuffer();
  286. appendClasspath(cp, aspectJars);
  287. cmd.add("-Daj.aspect.path=" + cp.toString());
  288. cp.append(classpath); // appendClasspath writes trailing delimiter
  289. cmd.add("-Daj.class.path=" + cp.toString());
  290. }
  291. cmd.add(spec.className);
  292. cmd.addAll(spec.options);
  293. String[] command = (String[]) cmd.toArray(new String[0]);
  294. final IMessageHandler handler = status;
  295. // setup to run asynchronously, pipe streams through, and report errors
  296. class DoneFlag {
  297. boolean done;
  298. boolean failed;
  299. int code;
  300. }
  301. final StringBuffer commandLabel = new StringBuffer();
  302. final DoneFlag doneFlag = new DoneFlag();
  303. LangUtil.ProcessController controller
  304. = new LangUtil.ProcessController() {
  305. protected void doCompleting(Thrown ex, int result) {
  306. if (!ex.thrown && (0 == result)) {
  307. doneFlag.done = true;
  308. return; // no errors
  309. }
  310. // handle errors
  311. String context = spec.className
  312. + " command \""
  313. + commandLabel
  314. + "\"";
  315. if (null != ex.fromProcess) {
  316. if (!expectedException(ex.fromProcess)) {
  317. String m = "Exception running " + context;
  318. MessageUtil.abort(handler, m, ex.fromProcess);
  319. doneFlag.failed = true;
  320. }
  321. } else if (0 != result) {
  322. doneFlag.code = result;
  323. }
  324. if (null != ex.fromInPipe) {
  325. String m = "Error processing input pipe for " + context;
  326. MessageUtil.abort(handler, m, ex.fromInPipe);
  327. doneFlag.failed = true;
  328. }
  329. if (null != ex.fromOutPipe) {
  330. String m = "Error processing output pipe for " + context;
  331. MessageUtil.abort(handler, m, ex.fromOutPipe);
  332. doneFlag.failed = true;
  333. }
  334. if (null != ex.fromErrPipe) {
  335. String m = "Error processing error pipe for " + context;
  336. MessageUtil.abort(handler, m, ex.fromErrPipe);
  337. doneFlag.failed = true;
  338. }
  339. doneFlag.done = true;
  340. }
  341. };
  342. controller.init(command, spec.className);
  343. if (null != spec.forkSpec.javaHome) {
  344. controller.setEnvp(new String[] {"JAVA_HOME=" + spec.forkSpec.javaHome});
  345. }
  346. commandLabel.append(Arrays.asList(controller.getCommand()).toString());
  347. final ByteArrayOutputStream errSnoop
  348. = new ByteArrayOutputStream();
  349. final ByteArrayOutputStream outSnoop
  350. = new ByteArrayOutputStream();
  351. controller.setErrSnoop(errSnoop);
  352. controller.setOutSnoop(outSnoop);
  353. controller.start();
  354. // give it 3 minutes...
  355. long maxTime = System.currentTimeMillis() + 3 * 60 * 1000;
  356. boolean waitingForStop = false;
  357. while (!doneFlag.done) {
  358. if (maxTime < System.currentTimeMillis()) {
  359. if (waitingForStop) { // hit second timeout - bail
  360. break;
  361. }
  362. MessageUtil.fail(status, "timeout waiting for process");
  363. doneFlag.failed = true;
  364. controller.stop();
  365. // wait 1 minute to evaluate results of stopping
  366. waitingForStop = true;
  367. maxTime = System.currentTimeMillis() + 1 * 60 * 1000;
  368. }
  369. try {
  370. Thread.sleep(300);
  371. } catch (InterruptedException e) {
  372. // ignore
  373. }
  374. }
  375. boolean foundException = false;
  376. if (0 < errSnoop.size()) {
  377. if (expectedException(errSnoop)) {
  378. foundException = true;
  379. } else if (spec.errStreamIsError) {
  380. MessageUtil.error(handler, errSnoop.toString());
  381. if (!doneFlag.failed) {
  382. doneFlag.failed = true;
  383. }
  384. } else {
  385. MessageUtil.info(handler, "Error stream: " + errSnoop.toString());
  386. }
  387. }
  388. if (0 < outSnoop.size()) {
  389. if (expectedException(outSnoop)) {
  390. foundException = true;
  391. } else if (spec.outStreamIsError) {
  392. MessageUtil.error(handler, outSnoop.toString());
  393. if (!doneFlag.failed) {
  394. doneFlag.failed = true;
  395. }
  396. } else {
  397. MessageUtil.info(handler, "Output stream: " + outSnoop.toString());
  398. }
  399. }
  400. if (!foundException) {
  401. if (null != spec.expectedException) {
  402. String m = " expected exception " + spec.expectedException;
  403. MessageUtil.fail(handler, m);
  404. doneFlag.failed = true;
  405. } else if (0 != doneFlag.code) {
  406. String m = doneFlag.code + " result from " + commandLabel;
  407. MessageUtil.fail(handler, m);
  408. doneFlag.failed = true;
  409. }
  410. }
  411. if (doneFlag.failed) {
  412. MessageUtil.info(handler, "other-vm command-line: " + commandLabel);
  413. }
  414. return !doneFlag.failed;
  415. }
  416. protected boolean expectedException(Throwable thrown) {
  417. if (null != spec.expectedException) {
  418. String cname = thrown.getClass().getName();
  419. if (-1 != cname.indexOf(spec.expectedException)) {
  420. return true; // caller sets value for returns normally
  421. }
  422. }
  423. return false;
  424. }
  425. protected boolean expectedException(ByteArrayOutputStream bout) {
  426. return ((null != spec.expectedException)
  427. && (-1 != bout.toString().indexOf(spec.expectedException)));
  428. }
  429. /**
  430. * Clear (static) testing state and setup base directory,
  431. * unless spec.skipTesting.
  432. * @return null if successful, error message otherwise
  433. */
  434. protected void setupTester(File baseDir, ClassLoader loader, IMessageHandler handler) {
  435. if (null == loader) {
  436. setupTester(baseDir, handler);
  437. return;
  438. }
  439. File baseDirSet = null;
  440. try {
  441. if (!spec.skipTester) {
  442. Class tc = loader.loadClass("org.aspectj.testing.Tester");
  443. // Tester.clear();
  444. Method m = tc.getMethod("clear", new Class[0]);
  445. m.invoke(null, new Object[0]);
  446. // Tester.setMessageHandler(handler);
  447. m = tc.getMethod("setMessageHandler", new Class[] {IMessageHandler.class});
  448. m.invoke(null, new Object[] { handler});
  449. //Tester.setBASEDIR(baseDir);
  450. m = tc.getMethod("setBASEDIR", new Class[] {File.class});
  451. m.invoke(null, new Object[] { baseDir});
  452. //baseDirSet = Tester.getBASEDIR();
  453. m = tc.getMethod("getBASEDIR", new Class[0]);
  454. baseDirSet = (File) m.invoke(null, new Object[0]);
  455. if (!baseDirSet.equals(baseDir)) {
  456. String l = "AjcScript.setupTester() setting "
  457. + baseDir + " returned " + baseDirSet;
  458. MessageUtil.debug(handler, l);
  459. }
  460. }
  461. } catch (Throwable t) {
  462. MessageUtil.abort(handler, "baseDir=" + baseDir, t);
  463. }
  464. }
  465. /**
  466. * Clear (static) testing state and setup base directory,
  467. * unless spec.skipTesting.
  468. * This implementation assumes that Tester is defined for the
  469. * same class loader as this class.
  470. * @return null if successful, error message otherwise
  471. */
  472. protected void setupTester(File baseDir, IMessageHandler handler) {
  473. File baseDirSet = null;
  474. try {
  475. if (!spec.skipTester) {
  476. Tester.clear();
  477. Tester.setMessageHandler(handler);
  478. Tester.setBASEDIR(baseDir);
  479. baseDirSet = Tester.getBASEDIR();
  480. if (!baseDirSet.equals(baseDir)) {
  481. String l = "AjcScript.setupTester() setting "
  482. + baseDir + " returned " + baseDirSet;
  483. MessageUtil.debug(handler, l);
  484. }
  485. }
  486. } catch (Throwable t) {
  487. MessageUtil.abort(handler, "baseDir=" + baseDir, t);
  488. }
  489. }
  490. public String toString() {
  491. return "JavaRun(" + spec + ")";
  492. }
  493. /**
  494. * Struct class for fork attributes and initialization.
  495. * This supports defaults for forking using system properties
  496. * which will be overridden by any specification.
  497. * (It differs from CompilerRun, which supports option
  498. * overriding by passing values as harness arguments.)
  499. */
  500. public static class ForkSpec {
  501. /**
  502. * key for system property for default value for forking
  503. * (true if set to true)
  504. */
  505. public static String FORK_KEY = "javarun.fork";
  506. public static String JAVA_KEY = "javarun.java";
  507. public static String VM_ARGS_KEY = "javarun.vmargs";
  508. public static String JAVA_HOME_KEY = "javarun.java.home";
  509. public static String BOOTCLASSPATH_KEY = "javarun.bootclasspath";
  510. static final ForkSpec FORK;
  511. static {
  512. ForkSpec fork = new ForkSpec();
  513. fork.fork = Boolean.getBoolean(FORK_KEY);
  514. fork.java = getFile(JAVA_KEY);
  515. if (null == fork.java) {
  516. fork.java = LangUtil.getJavaExecutable();
  517. }
  518. fork.javaHome = getFile(JAVA_HOME_KEY);
  519. fork.bootclasspath = XMLWriter.unflattenList(getProperty(BOOTCLASSPATH_KEY));
  520. fork.vmargs = XMLWriter.unflattenList(getProperty(VM_ARGS_KEY));
  521. FORK = fork;
  522. }
  523. private static File getFile(String key) {
  524. String path = getProperty(key);
  525. if (null != path) {
  526. File result = new File(path);
  527. if (result.exists()) {
  528. return result;
  529. }
  530. }
  531. return null;
  532. }
  533. private static String getProperty(String key) {
  534. try {
  535. return System.getProperty(key);
  536. } catch (Throwable t) {
  537. return null;
  538. }
  539. }
  540. private boolean fork;
  541. private String[] bootclasspath;
  542. private File java;
  543. private File javaHome;
  544. private String[] vmargs;
  545. private ForkSpec() {
  546. copy(FORK);
  547. }
  548. private void copy(ForkSpec forkSpec) {
  549. if (null != forkSpec) {
  550. fork = forkSpec.fork;
  551. bootclasspath = forkSpec.bootclasspath;
  552. java = forkSpec.java;
  553. javaHome = forkSpec.javaHome;
  554. vmargs = forkSpec.vmargs;
  555. }
  556. }
  557. /**
  558. * @return "" or bootclasspath with File.pathSeparator internal delimiters
  559. */
  560. String getBootclasspath() {
  561. if (LangUtil.isEmpty(bootclasspath)) {
  562. return "";
  563. }
  564. return FileUtil.flatten(bootclasspath, null);
  565. }
  566. }
  567. /**
  568. * Initializer/factory for JavaRun.
  569. * The classpath is not here but precalculated in the Sandbox.
  570. */
  571. public static class Spec extends AbstractRunSpec {
  572. static {
  573. try {
  574. System.setSecurityManager(RunSecurityManager.ME);
  575. } catch (Throwable t) {
  576. System.err.println("JavaRun: Security manager set - no System.exit() protection");
  577. }
  578. }
  579. public static final String XMLNAME = "run";
  580. /**
  581. * skip description, skip sourceLocation,
  582. * do keywords, do options, skip paths, do comment,
  583. * skip staging, skip badInput,
  584. * do dirChanges, do messages but skip children.
  585. */
  586. private static final XMLNames NAMES = new XMLNames(XMLNames.DEFAULT,
  587. "", "", null, null, "", null, "", "", false, false, true);
  588. /** fully-qualified name of the class to run */
  589. protected String className;
  590. /** Alternative to classname for specifying what to run modulename/type */
  591. protected String module;
  592. /** minimum required version of Java, if any */
  593. protected String javaVersion;
  594. /** if true, skip Tester setup (e.g., if Tester n/a) */
  595. protected boolean skipTester;
  596. /** if true, report text to output stream as error */
  597. protected boolean outStreamIsError;
  598. /** if true, report text to error stream as error */
  599. protected boolean errStreamIsError = true;
  600. protected final ForkSpec forkSpec;
  601. protected String[] aspectpath;
  602. protected boolean useLTW;
  603. protected String[] classpath;
  604. protected String expectedException;
  605. public Spec() {
  606. super(XMLNAME);
  607. setXMLNames(NAMES);
  608. forkSpec = new ForkSpec();
  609. }
  610. protected void initClone(Spec spec)
  611. throws CloneNotSupportedException {
  612. super.initClone(spec);
  613. spec.className = className;
  614. spec.errStreamIsError = errStreamIsError;
  615. spec.javaVersion = javaVersion;
  616. spec.outStreamIsError = outStreamIsError;
  617. spec.skipTester = skipTester;
  618. spec.forkSpec.copy(forkSpec);
  619. }
  620. public Object clone() throws CloneNotSupportedException {
  621. Spec result = new Spec();
  622. initClone(result);
  623. return result;
  624. }
  625. public boolean isLTW() {
  626. return useLTW || (null != aspectpath);
  627. }
  628. /**
  629. * @param version "1.1", "1.2", "1.3", "1.4"
  630. * @throws IllegalArgumentException if version is not recognized
  631. */
  632. public void setJavaVersion(String version) {
  633. Globals.supportsJava(version);
  634. this.javaVersion = version;
  635. }
  636. /** @className fully-qualified name of the class to run */
  637. public void setClassName(String className) {
  638. this.className = className;
  639. }
  640. public void setModule(String module) {
  641. this.module = module;
  642. }
  643. public void setLTW(String ltw) {
  644. useLTW = TestUtil.parseBoolean(ltw);
  645. }
  646. public void setAspectpath(String path) {
  647. this.aspectpath = XMLWriter.unflattenList(path);
  648. }
  649. public void setException(String exception) {
  650. this.expectedException = exception;
  651. }
  652. public void setClasspath(String path) {
  653. this.classpath = XMLWriter.unflattenList(path);
  654. }
  655. public void setErrStreamIsError(String errStreamIsError) {
  656. this.errStreamIsError = TestUtil.parseBoolean(errStreamIsError);
  657. }
  658. public void setOutStreamIsError(String outStreamIsError) {
  659. this.outStreamIsError = TestUtil.parseBoolean(outStreamIsError);
  660. }
  661. /** @param skip if true, then do not set up Tester */
  662. public void setSkipTester(boolean skip) {
  663. skipTester = skip;
  664. }
  665. public void setFork(boolean fork) {
  666. forkSpec.fork = fork;
  667. }
  668. /**
  669. * @param vmargs comma-delimited list of arguments for java,
  670. * typically -Dname=value,-DanotherName="another value"
  671. */
  672. public void setVmArgs(String vmargs) {
  673. forkSpec.vmargs = XMLWriter.unflattenList(vmargs);
  674. }
  675. /** override to set dirToken to Sandbox.RUN_DIR */
  676. public void addDirChanges(DirChanges.Spec spec) {
  677. if (null == spec) {
  678. return;
  679. }
  680. spec.setDirToken(Sandbox.RUN_DIR);
  681. super.addDirChanges(spec);
  682. }
  683. /** @return a JavaRun with this as spec if setup completes successfully. */
  684. public IRunIterator makeRunIterator(Sandbox sandbox, Validator validator) {
  685. JavaRun run = new JavaRun(this);
  686. if (run.setupAjcRun(sandbox, validator)) {
  687. // XXX need name for JavaRun
  688. return new WrappedRunIterator(this, run);
  689. }
  690. return null;
  691. }
  692. /**
  693. * Write this out as a run element as defined in
  694. * AjcSpecXmlReader.DOCTYPE.
  695. * @see AjcSpecXmlReader#DOCTYPE
  696. * @see IXmlWritable#writeXml(XMLWriter)
  697. */
  698. public void writeXml(XMLWriter out) {
  699. String attr = XMLWriter.makeAttribute("class", className);
  700. out.startElement(xmlElementName, attr, false);
  701. if (skipTester) {
  702. out.printAttribute("skipTester", "true");
  703. }
  704. if (null != javaVersion) {
  705. out.printAttribute("vm", javaVersion);
  706. }
  707. if (outStreamIsError) {
  708. out.printAttribute("outStreamIsError", "true");
  709. }
  710. if (!errStreamIsError) { // defaults to true
  711. out.printAttribute("errStreamIsError", "false");
  712. }
  713. super.writeAttributes(out);
  714. out.endAttributes();
  715. if (!LangUtil.isEmpty(dirChanges)) {
  716. DirChanges.Spec.writeXml(out, dirChanges);
  717. }
  718. SoftMessage.writeXml(out, getMessages());
  719. out.endElement(xmlElementName);
  720. }
  721. public String toLongString() {
  722. return toString() + "[" + super.toLongString() + "]";
  723. }
  724. public String toString() {
  725. if (skipTester) {
  726. return "JavaRun(" + className + ", skipTester)";
  727. } else {
  728. return "JavaRun(" + className + ")";
  729. }
  730. }
  731. /**
  732. * This implementation skips if:
  733. * <ul>
  734. * <li>current VM is not at least any specified javaVersion </li>
  735. * </ul>
  736. * @return false if this wants to be skipped, true otherwise
  737. */
  738. protected boolean doAdoptParentValues(RT parentRuntime, IMessageHandler handler) {
  739. if (!super.doAdoptParentValues(parentRuntime, handler)) {
  740. return false;
  741. }
  742. if ((null != javaVersion) && (!Globals.supportsJava(javaVersion))) {
  743. skipMessage(handler, "requires Java version " + javaVersion);
  744. return false;
  745. }
  746. return true;
  747. }
  748. }
  749. /**
  750. * This permits everything but System.exit() in the context of a
  751. * thread set by JavaRun.
  752. * XXX need to update for thread spawned by that thread
  753. * XXX need to update for awt thread use after AJDE wrapper doesn't
  754. */
  755. public static class RunSecurityManager extends SecurityManager {
  756. public static RunSecurityManager ME = new RunSecurityManager();
  757. private Thread runThread;
  758. private RunSecurityManager(){}
  759. private synchronized void setJavaRunThread(JavaRun run) {
  760. LangUtil.throwIaxIfNull(run, "run");
  761. runThread = Thread.currentThread();
  762. }
  763. private synchronized void releaseJavaRunThread(JavaRun run) {
  764. LangUtil.throwIaxIfNull(run, "run");
  765. runThread = null;
  766. }
  767. /** @throws ExitCalledException if called from the JavaRun-set thread */
  768. public void checkExit(int exitCode) throws ExitCalledException {
  769. if ((null != runThread) && runThread.equals(Thread.currentThread())) {
  770. throw new ExitCalledException(exitCode);
  771. }
  772. }
  773. public void checkAwtEventQueueAccess() {
  774. if ((null != runThread) && runThread.equals(Thread.currentThread())) {
  775. throw new AwtUsedException();
  776. }
  777. }
  778. public void checkSystemClipboardAccess() {
  779. // permit
  780. }
  781. // used by constrained calls
  782. public static class ExitCalledException extends SecurityException {
  783. public final int exitCode;
  784. public ExitCalledException(int exitCode) {
  785. this.exitCode = exitCode;
  786. }
  787. }
  788. public static class AwtUsedException extends SecurityException {
  789. public AwtUsedException() { }
  790. }
  791. // permit everything else
  792. public void checkAccept(String arg0, int arg1) {
  793. }
  794. public void checkAccess(Thread arg0) {
  795. }
  796. public void checkAccess(ThreadGroup arg0) {
  797. }
  798. public void checkConnect(String arg0, int arg1) {
  799. }
  800. public void checkConnect(String arg0, int arg1, Object arg2) {
  801. }
  802. public void checkCreateClassLoader() {
  803. }
  804. public void checkDelete(String arg0) {
  805. }
  806. public void checkExec(String arg0) {
  807. }
  808. public void checkLink(String arg0) {
  809. }
  810. public void checkListen(int arg0) {
  811. }
  812. public void checkMemberAccess(Class arg0, int arg1) {
  813. }
  814. public void checkMulticast(InetAddress arg0) {
  815. }
  816. public void checkMulticast(InetAddress arg0, byte arg1) {
  817. }
  818. public void checkPackageAccess(String arg0) {
  819. }
  820. public void checkPackageDefinition(String arg0) {
  821. }
  822. public void checkPermission(Permission arg0) {
  823. }
  824. public void checkPermission(Permission arg0, Object arg1) {
  825. }
  826. public void checkPrintJobAccess() {
  827. }
  828. public void checkPropertiesAccess() {
  829. }
  830. public void checkPropertyAccess(String arg0) {
  831. }
  832. public void checkRead(FileDescriptor arg0) {
  833. }
  834. public void checkRead(String arg0) {
  835. }
  836. public void checkRead(String arg0, Object arg1) {
  837. }
  838. public void checkSecurityAccess(String arg0) {
  839. }
  840. public void checkSetFactory() {
  841. }
  842. public boolean checkTopLevelWindow(Object arg0) {
  843. return true;
  844. }
  845. public void checkWrite(FileDescriptor arg0) {
  846. }
  847. public void checkWrite(String arg0) {
  848. }
  849. }
  850. }