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 29KB

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