JavaRun.java
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* Xerox/PARC initial implementation
* ******************************************************************/
package org.aspectj.testing.harness.bridge;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URL;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Arrays;
import org.aspectj.bridge.AbortException;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.testing.Tester;
import org.aspectj.testing.run.IRunIterator;
import org.aspectj.testing.run.IRunStatus;
import org.aspectj.testing.run.WrappedRunIterator;
import org.aspectj.testing.util.TestClassLoader;
import org.aspectj.testing.util.TestUtil;
import org.aspectj.testing.xml.SoftMessage;
import org.aspectj.testing.xml.XMLWriter;
import org.aspectj.util.FileUtil;
import org.aspectj.util.LangUtil;
import org.aspectj.weaver.loadtime.WeavingURLClassLoader;
/**
* Run a class in this VM using reflection.
* Forked mode supported, but through system properties:
* - javarun.fork: anything to enable forking
* - javarun.java: path to java executable (optional)
* - javarun.java.home: JAVA_HOME for java (optional)
* (normally requires javarun.java)
* - javarun.classpath: a prefix to the run classpath (optional)
*/
public class JavaRun implements IAjcRun {
private static void appendClasspath(StringBuffer cp, Object[] entries) {
if (!LangUtil.isEmpty(entries)) {
for (Object entry : entries) {
if (entry instanceof String) {
cp.append((String) entry);
cp.append(File.pathSeparator);
} else if (entry instanceof File) {
String s = FileUtil.getBestPath((File) entry);
if (null != s) {
cp.append(s);
cp.append(File.pathSeparator);
}
}
}
}
}
Spec spec;
private Sandbox sandbox;
/** programmatic initialization per spec */
public JavaRun(Spec spec) {
this.spec = spec;
}
// XXX init(Spec)
/**
* This checks the spec for a class name
* and checks the sandbox for a readable test source directory,
* a writable run dir, and (non-null, possibly-empty) lists
* of readable classpath dirs and jars,
* and, if fork is enabled, that java can be read.
* @return true if all checks pass
* @see org.aspectj.testing.harness.bridge.AjcTest.IAjcRun#setup(File, File)
*/
@Override
public boolean setupAjcRun(Sandbox sandbox, Validator validator) {
this.sandbox = sandbox;
sandbox.javaRunInit(this);
return (validator.nullcheck(spec.className, "class name")
&& validator.nullcheck(sandbox, "sandbox")
&& validator.canReadDir(sandbox.getTestBaseSrcDir(this), "testBaseSrc dir")
&& validator.canWriteDir(sandbox.runDir, "run dir")
&& validator.canReadFiles(sandbox.getClasspathJars(true, this), "classpath jars")
&& validator.canReadDirs(sandbox.getClasspathDirectories(true, this, true), "classpath dirs")
&& (!spec.forkSpec.fork
|| validator.canRead(spec.forkSpec.java, "java"))
);
}
/** caller must record any exceptions */
@Override
public boolean run(IRunStatus status)
throws IllegalAccessException,
InvocationTargetException,
ClassNotFoundException,
NoSuchMethodException {
boolean completedNormally = false;
boolean passed = false;
if (!LangUtil.isEmpty(spec.dirChanges)) {
MessageUtil.info(status, "XXX dirChanges not implemented in JavaRun");
}
try {
final boolean readable = true;
File[] libs = sandbox.getClasspathJars(readable, this);
boolean includeClassesDir = true;
File[] dirs = sandbox.getClasspathDirectories(readable, this, includeClassesDir);
completedNormally = (spec.forkSpec.fork)
? runInOtherVM(status, libs, dirs)
: runInSameVM(status, libs, dirs);
passed = completedNormally;
} finally {
if (!passed || !status.runResult()) {
MessageUtil.info(status, spec.toLongString());
MessageUtil.info(status, "sandbox: " + sandbox);
}
}
return passed;
}
protected boolean runInSameVM(IRunStatus status, File[] libs, File[] dirs) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
ClassLoader loader = null;
boolean completedNormally = false;
boolean passed = false;
ByteArrayOutputStream outSnoop = null;
PrintStream oldOut = null;
ByteArrayOutputStream errSnoop = null;
PrintStream oldErr = null;
if (spec.outStreamIsError) {
outSnoop = new ByteArrayOutputStream();
oldOut = System.out;
System.setOut(new PrintStream(outSnoop, true));
}
if (spec.errStreamIsError) {
errSnoop = new ByteArrayOutputStream();
oldErr = System.err;
System.setErr(new PrintStream(errSnoop, true));
}
Class targetClass = null;
try {
final URL[] clAndLibs;
{
File[] files = sandbox.findFiles(spec.classpath);
URL[] clURLs = FileUtil.getFileURLs(files);
URL[] libURLs = FileUtil.getFileURLs(libs);
clAndLibs = new URL[clURLs.length + libURLs.length];
System.arraycopy(clURLs, 0, clAndLibs , 0, clURLs.length);
System.arraycopy(libURLs, 0, clAndLibs, clURLs.length, libURLs.length);
}
if (!spec.isLTW()) {
loader = new TestClassLoader(clAndLibs, dirs);
} else {
final URL[] aspectURLs;
{
File[] files = sandbox.findFiles(spec.aspectpath);
aspectURLs = FileUtil.getFileURLs(files);
}
ArrayList classpath = new ArrayList(Arrays.asList(aspectURLs));
final URL[] classURLs;
{
classpath.addAll(Arrays.asList(clAndLibs));
URL[] urls = FileUtil.getFileURLs(dirs);
classpath.addAll(Arrays.asList(urls));
classpath.add(FileUtil.getFileURL(Globals.F_aspectjrt_jar));
classpath.add(FileUtil.getFileURL(Globals.F_testingclient_jar));
classURLs = (URL[]) classpath.toArray(new URL[0]);
}
ClassLoader parent = JavaRun.class.getClassLoader();
loader = new WeavingURLClassLoader(classURLs, aspectURLs, parent);
}
// make the following load test optional
// Class testAspect = loader.loadClass("org.aspectj.lang.JoinPoint");
targetClass = loader.loadClass(spec.className);
Method main = targetClass.getMethod("main", Globals.MAIN_PARM_TYPES);
setupTester(sandbox.getTestBaseSrcDir(this), loader, status);
RunSecurityManager.ME.setJavaRunThread(this);
main.invoke(null, new Object[] { spec.getOptionsArray() });
completedNormally = true;
boolean snoopFailure =
((null != errSnoop) && 0 < errSnoop.size())
|| ((null != outSnoop) && 0 < outSnoop.size());
passed = !snoopFailure && (null == spec.expectedException);
} catch (AbortException e) {
if (expectedException(e)) {
passed = true;
} else {
throw e;
}
} catch (InvocationTargetException e) {
// this and following clauses catch ExitCalledException
Throwable thrown = LangUtil.unwrapException(e);
if (null == thrown) {
throw e;
}
if (thrown instanceof RunSecurityManager.ExitCalledException) {
int i = ((RunSecurityManager.ExitCalledException) thrown).exitCode;
status.finish(i);
} else if (thrown instanceof RunSecurityManager.AwtUsedException) {
MessageUtil.fail(status, "test code should not use the AWT event queue");
throw (RunSecurityManager.AwtUsedException) thrown;
// same as: status.thrown(thrown);
} else if (expectedException(thrown)) {
passed = true;
} else if (thrown instanceof RuntimeException) {
throw (RuntimeException) thrown;
} else if (thrown instanceof Error) {
throw (Error) thrown;
} else {
throw e;
}
} catch (RunSecurityManager.ExitCalledException e) {
// XXX need to update run validator (a) to accept null result or (b) to require zero result, and set 0 if completed normally
status.finish(e.exitCode);
} catch (ClassNotFoundException e) {
String[] classes = FileUtil.listFiles(sandbox.classesDir);
MessageUtil.info(status, "sandbox.classes: " + Arrays.asList(classes));
MessageUtil.fail(status, null, e);
} finally {
if (null != oldOut) {
System.setOut(oldOut);
}
if (null != oldErr) {
System.setErr(oldErr);
}
RunSecurityManager.ME.releaseJavaRunThread(this);
if (!completedNormally) {
MessageUtil.info(status, "targetClass: " + targetClass);
MessageUtil.info(status, "loader: " + loader);
}
}
return passed;
}
/**
* Run in another VM by grabbing Java, bootclasspath, classpath, etc.
* This assumes any exception or output to System.err is a failure,
* and any normal completion is a pass.
* @param status
* @param libs
* @param dirs
* @return
*/
protected boolean runInOtherVM(IRunStatus status, File[] libs, File[] dirs) {
// assert spec.fork || !LangUtil.isEmpty(spec.aspectpath);
ArrayList<String> cmd = new ArrayList<>();
cmd.add(FileUtil.getBestPath(spec.forkSpec.java));
if (!LangUtil.isEmpty(spec.forkSpec.vmargs)) {
cmd.addAll(Arrays.asList(spec.forkSpec.vmargs));
}
final String classpath;
{
StringBuffer cp = new StringBuffer();
appendClasspath(cp, spec.forkSpec.bootclasspath);
appendClasspath(cp, dirs);
appendClasspath(cp, libs);
File[] classpathFiles = sandbox.findFiles(spec.classpath);
int cpLength = (null == classpathFiles ? 0 : classpathFiles.length);
int spLength = (null == spec.classpath ? 0 : spec.classpath.length);
if (cpLength != spLength) {
throw new Error("unable to find " + Arrays.asList(spec.classpath)
+ " got " + Arrays.asList(classpathFiles));
}
appendClasspath(cp, classpathFiles);
File[] stdlibs = {Globals.F_aspectjrt_jar, Globals.F_testingclient_jar};
appendClasspath(cp, stdlibs);
classpath = cp.toString();
}
if (!spec.isLTW()) {
cmd.add("-classpath");
cmd.add(classpath);
} else {
// verify 1.4 or above, assuming same vm as running this
if (!Globals.supportsJava("1.4")) {
throw new Error("load-time weaving test requires Java 1.4+");
}
cmd.add("-Djava.system.class.loader=org.aspectj.weaver.WeavingURLClassLoader");
// assume harness VM classpath has WeavingURLClassLoader (but not others)
cmd.add("-classpath");
cmd.add(System.getProperty("java.class.path"));
File[] aspectJars = sandbox.findFiles(spec.aspectpath);
if (aspectJars.length != spec.aspectpath.length) {
throw new Error("unable to find " + Arrays.asList(spec.aspectpath));
}
StringBuffer cp = new StringBuffer();
appendClasspath(cp, aspectJars);
cmd.add("-Daj.aspect.path=" + cp.toString());
cp.append(classpath); // appendClasspath writes trailing delimiter
cmd.add("-Daj.class.path=" + cp.toString());
}
cmd.add(spec.className);
cmd.addAll(spec.options);
String[] command = cmd.toArray(new String[0]);
final IMessageHandler handler = status;
// setup to run asynchronously, pipe streams through, and report errors
class DoneFlag {
boolean done;
boolean failed;
int code;
}
final StringBuffer commandLabel = new StringBuffer();
final DoneFlag doneFlag = new DoneFlag();
LangUtil.ProcessController controller
= new LangUtil.ProcessController() {
@Override
protected void doCompleting(Thrown ex, int result) {
if (!ex.thrown && (0 == result)) {
doneFlag.done = true;
return; // no errors
}
// handle errors
String context = spec.className
+ " command \""
+ commandLabel
+ "\"";
if (null != ex.fromProcess) {
if (!expectedException(ex.fromProcess)) {
String m = "Exception running " + context;
MessageUtil.abort(handler, m, ex.fromProcess);
doneFlag.failed = true;
}
} else if (0 != result) {
doneFlag.code = result;
}
if (null != ex.fromInPipe) {
String m = "Error processing input pipe for " + context;
MessageUtil.abort(handler, m, ex.fromInPipe);
doneFlag.failed = true;
}
if (null != ex.fromOutPipe) {
String m = "Error processing output pipe for " + context;
MessageUtil.abort(handler, m, ex.fromOutPipe);
doneFlag.failed = true;
}
if (null != ex.fromErrPipe) {
String m = "Error processing error pipe for " + context;
MessageUtil.abort(handler, m, ex.fromErrPipe);
doneFlag.failed = true;
}
doneFlag.done = true;
}
};
controller.init(command, spec.className);
if (null != spec.forkSpec.javaHome) {
controller.setEnvp(new String[] {"JAVA_HOME=" + spec.forkSpec.javaHome});
}
commandLabel.append(Arrays.asList(controller.getCommand()).toString());
final ByteArrayOutputStream errSnoop
= new ByteArrayOutputStream();
final ByteArrayOutputStream outSnoop
= new ByteArrayOutputStream();
controller.setErrSnoop(errSnoop);
controller.setOutSnoop(outSnoop);
controller.start();
// give it 3 minutes...
long maxTime = System.currentTimeMillis() + 3 * 60 * 1000;
boolean waitingForStop = false;
while (!doneFlag.done) {
if (maxTime < System.currentTimeMillis()) {
if (waitingForStop) { // hit second timeout - bail
break;
}
MessageUtil.fail(status, "timeout waiting for process");
doneFlag.failed = true;
controller.stop();
// wait 1 minute to evaluate results of stopping
waitingForStop = true;
maxTime = System.currentTimeMillis() + 1 * 60 * 1000;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// ignore
}
}
boolean foundException = false;
if (0 < errSnoop.size()) {
if (expectedException(errSnoop)) {
foundException = true;
} else if (spec.errStreamIsError) {
MessageUtil.error(handler, errSnoop.toString());
if (!doneFlag.failed) {
doneFlag.failed = true;
}
} else {
MessageUtil.info(handler, "Error stream: " + errSnoop.toString());
}
}
if (0 < outSnoop.size()) {
if (expectedException(outSnoop)) {
foundException = true;
} else if (spec.outStreamIsError) {
MessageUtil.error(handler, outSnoop.toString());
if (!doneFlag.failed) {
doneFlag.failed = true;
}
} else {
MessageUtil.info(handler, "Output stream: " + outSnoop.toString());
}
}
if (!foundException) {
if (null != spec.expectedException) {
String m = " expected exception " + spec.expectedException;
MessageUtil.fail(handler, m);
doneFlag.failed = true;
} else if (0 != doneFlag.code) {
String m = doneFlag.code + " result from " + commandLabel;
MessageUtil.fail(handler, m);
doneFlag.failed = true;
}
}
if (doneFlag.failed) {
MessageUtil.info(handler, "other-vm command-line: " + commandLabel);
}
return !doneFlag.failed;
}
protected boolean expectedException(Throwable thrown) {
if (null != spec.expectedException) {
String cname = thrown.getClass().getName();
if (cname.contains(spec.expectedException)) {
return true; // caller sets value for returns normally
}
}
return false;
}
protected boolean expectedException(ByteArrayOutputStream bout) {
return ((null != spec.expectedException)
&& (bout.toString().contains(spec.expectedException)));
}
/**
* Clear (static) testing state and setup base directory,
* unless spec.skipTesting.
* @return null if successful, error message otherwise
*/
protected void setupTester(File baseDir, ClassLoader loader, IMessageHandler handler) {
if (null == loader) {
setupTester(baseDir, handler);
return;
}
File baseDirSet = null;
try {
if (!spec.skipTester) {
Class tc = loader.loadClass("org.aspectj.testing.Tester");
// Tester.clear();
Method m = tc.getMethod("clear", new Class[0]);
m.invoke(null, new Object[0]);
// Tester.setMessageHandler(handler);
m = tc.getMethod("setMessageHandler", new Class[] {IMessageHandler.class});
m.invoke(null, new Object[] { handler});
//Tester.setBASEDIR(baseDir);
m = tc.getMethod("setBASEDIR", new Class[] {File.class});
m.invoke(null, new Object[] { baseDir});
//baseDirSet = Tester.getBASEDIR();
m = tc.getMethod("getBASEDIR", new Class[0]);
baseDirSet = (File) m.invoke(null, new Object[0]);
if (!baseDirSet.equals(baseDir)) {
String l = "AjcScript.setupTester() setting "
+ baseDir + " returned " + baseDirSet;
MessageUtil.debug(handler, l);
}
}
} catch (Throwable t) {
MessageUtil.abort(handler, "baseDir=" + baseDir, t);
}
}
/**
* Clear (static) testing state and setup base directory,
* unless spec.skipTesting.
* This implementation assumes that Tester is defined for the
* same class loader as this class.
* @return null if successful, error message otherwise
*/
protected void setupTester(File baseDir, IMessageHandler handler) {
File baseDirSet = null;
try {
if (!spec.skipTester) {
Tester.clear();
Tester.setMessageHandler(handler);
Tester.setBASEDIR(baseDir);
baseDirSet = Tester.getBASEDIR();
if (!baseDirSet.equals(baseDir)) {
String l = "AjcScript.setupTester() setting "
+ baseDir + " returned " + baseDirSet;
MessageUtil.debug(handler, l);
}
}
} catch (Throwable t) {
MessageUtil.abort(handler, "baseDir=" + baseDir, t);
}
}
@Override
public String toString() {
return "JavaRun(" + spec + ")";
}
/**
* Struct class for fork attributes and initialization.
* This supports defaults for forking using system properties
* which will be overridden by any specification.
* (It differs from CompilerRun, which supports option
* overriding by passing values as harness arguments.)
*/
public static class ForkSpec {
/**
* key for system property for default value for forking
* (true if set to true)
*/
public static String FORK_KEY = "javarun.fork";
public static String JAVA_KEY = "javarun.java";
public static String VM_ARGS_KEY = "javarun.vmargs";
public static String JAVA_HOME_KEY = "javarun.java.home";
public static String BOOTCLASSPATH_KEY = "javarun.bootclasspath";
static final ForkSpec FORK;
static {
ForkSpec fork = new ForkSpec();
fork.fork = Boolean.getBoolean(FORK_KEY);
fork.java = getFile(JAVA_KEY);
if (null == fork.java) {
fork.java = LangUtil.getJavaExecutable();
}
fork.javaHome = getFile(JAVA_HOME_KEY);
fork.bootclasspath = XMLWriter.unflattenList(getProperty(BOOTCLASSPATH_KEY));
fork.vmargs = XMLWriter.unflattenList(getProperty(VM_ARGS_KEY));
FORK = fork;
}
private static File getFile(String key) {
String path = getProperty(key);
if (null != path) {
File result = new File(path);
if (result.exists()) {
return result;
}
}
return null;
}
private static String getProperty(String key) {
try {
return System.getProperty(key);
} catch (Throwable t) {
return null;
}
}
private boolean fork;
private String[] bootclasspath;
private File java;
private File javaHome;
private String[] vmargs;
private ForkSpec() {
copy(FORK);
}
private void copy(ForkSpec forkSpec) {
if (null != forkSpec) {
fork = forkSpec.fork;
bootclasspath = forkSpec.bootclasspath;
java = forkSpec.java;
javaHome = forkSpec.javaHome;
vmargs = forkSpec.vmargs;
}
}
/**
* @return "" or bootclasspath with File.pathSeparator internal delimiters
*/
String getBootclasspath() {
if (LangUtil.isEmpty(bootclasspath)) {
return "";
}
return FileUtil.flatten(bootclasspath, null);
}
}
/**
* Initializer/factory for JavaRun.
* The classpath is not here but precalculated in the Sandbox.
*/
public static class Spec extends AbstractRunSpec {
static {
try {
// TODO: Deprecate the Security Manager for Removal, see https://openjdk.java.net/jeps/411.
// As of Java 18, the new API for blocking System.exit is not available yet, see
// https://bugs.openjdk.java.net/browse/JDK-8199704.
System.setSecurityManager(RunSecurityManager.ME);
} catch (Throwable t) {
System.err.println("JavaRun: Security manager set - no System.exit() protection");
}
}
public static final String XMLNAME = "run";
/**
* skip description, skip sourceLocation,
* do keywords, do options, skip paths, do comment,
* skip staging, skip badInput,
* do dirChanges, do messages but skip children.
*/
private static final XMLNames NAMES = new XMLNames(XMLNames.DEFAULT,
"", "", null, null, "", null, "", "", false, false, true);
/** fully-qualified name of the class to run */
protected String className;
/** Alternative to classname for specifying what to run modulename/type */
protected String module;
/** minimum required version of Java, if any */
protected String javaVersion;
/** if true, skip Tester setup (e.g., if Tester n/a) */
protected boolean skipTester;
/** if true, report text to output stream as error */
protected boolean outStreamIsError;
/** if true, report text to error stream as error */
protected boolean errStreamIsError = true;
protected final ForkSpec forkSpec;
protected String[] aspectpath;
protected boolean useLTW;
protected String[] classpath;
protected String expectedException;
public Spec() {
super(XMLNAME);
setXMLNames(NAMES);
forkSpec = new ForkSpec();
}
protected void initClone(Spec spec)
throws CloneNotSupportedException {
super.initClone(spec);
spec.className = className;
spec.errStreamIsError = errStreamIsError;
spec.javaVersion = javaVersion;
spec.outStreamIsError = outStreamIsError;
spec.skipTester = skipTester;
spec.forkSpec.copy(forkSpec);
}
@Override
public Object clone() throws CloneNotSupportedException {
Spec result = new Spec();
initClone(result);
return result;
}
public boolean isLTW() {
return useLTW || (null != aspectpath);
}
/**
* @param version "1.1", "1.2", "1.3", "1.4"
* @throws IllegalArgumentException if version is not recognized
*/
public void setJavaVersion(String version) {
Globals.supportsJava(version);
this.javaVersion = version;
}
/** @className fully-qualified name of the class to run */
public void setClassName(String className) {
this.className = className;
}
public void setModule(String module) {
this.module = module;
}
public void setLTW(String ltw) {
useLTW = TestUtil.parseBoolean(ltw);
}
public void setAspectpath(String path) {
this.aspectpath = XMLWriter.unflattenList(path);
}
public void setException(String exception) {
this.expectedException = exception;
}
public void setClasspath(String path) {
this.classpath = XMLWriter.unflattenList(path);
}
public void setErrStreamIsError(String errStreamIsError) {
this.errStreamIsError = TestUtil.parseBoolean(errStreamIsError);
}
public void setOutStreamIsError(String outStreamIsError) {
this.outStreamIsError = TestUtil.parseBoolean(outStreamIsError);
}
/** @param skip if true, then do not set up Tester */
public void setSkipTester(boolean skip) {
skipTester = skip;
}
public void setFork(boolean fork) {
forkSpec.fork = fork;
}
/**
* @param vmargs comma-delimited list of arguments for java,
* typically -Dname=value,-DanotherName="another value"
*/
public void setVmArgs(String vmargs) {
forkSpec.vmargs = XMLWriter.unflattenList(vmargs);
}
/** override to set dirToken to Sandbox.RUN_DIR */
@Override
public void addDirChanges(DirChanges.Spec spec) {
if (null == spec) {
return;
}
spec.setDirToken(Sandbox.RUN_DIR);
super.addDirChanges(spec);
}
/** @return a JavaRun with this as spec if setup completes successfully. */
@Override
public IRunIterator makeRunIterator(Sandbox sandbox, Validator validator) {
JavaRun run = new JavaRun(this);
if (run.setupAjcRun(sandbox, validator)) {
// XXX need name for JavaRun
return new WrappedRunIterator(this, run);
}
return null;
}
/**
* Write this out as a run element as defined in
* AjcSpecXmlReader.DOCTYPE.
* @see AjcSpecXmlReader#DOCTYPE
* @see IXmlWritable#writeXml(XMLWriter)
*/
@Override
public void writeXml(XMLWriter out) {
String attr = XMLWriter.makeAttribute("class", className);
out.startElement(xmlElementName, attr, false);
if (skipTester) {
out.printAttribute("skipTester", "true");
}
if (null != javaVersion) {
out.printAttribute("vm", javaVersion);
}
if (outStreamIsError) {
out.printAttribute("outStreamIsError", "true");
}
if (!errStreamIsError) { // defaults to true
out.printAttribute("errStreamIsError", "false");
}
super.writeAttributes(out);
out.endAttributes();
if (!LangUtil.isEmpty(dirChanges)) {
DirChanges.Spec.writeXml(out, dirChanges);
}
SoftMessage.writeXml(out, getMessages());
out.endElement(xmlElementName);
}
@Override
public String toLongString() {
return toString() + "[" + super.toLongString() + "]";
}
@Override
public String toString() {
if (skipTester) {
return "JavaRun(" + className + ", skipTester)";
} else {
return "JavaRun(" + className + ")";
}
}
/**
* This implementation skips if:
* <ul>
* <li>current VM is not at least any specified javaVersion </li>
* </ul>
* @return false if this wants to be skipped, true otherwise
*/
@Override
protected boolean doAdoptParentValues(RT parentRuntime, IMessageHandler handler) {
if (!super.doAdoptParentValues(parentRuntime, handler)) {
return false;
}
if ((null != javaVersion) && (!Globals.supportsJava(javaVersion))) {
skipMessage(handler, "requires Java version " + javaVersion);
return false;
}
return true;
}
}
/**
* This permits everything but System.exit() in the context of a
* thread set by JavaRun.
* XXX need to update for thread spawned by that thread
* XXX need to update for awt thread use after AJDE wrapper doesn't
*/
public static class RunSecurityManager extends SecurityManager {
public static RunSecurityManager ME = new RunSecurityManager();
private Thread runThread;
private RunSecurityManager(){}
private synchronized void setJavaRunThread(JavaRun run) {
LangUtil.throwIaxIfNull(run, "run");
runThread = Thread.currentThread();
}
private synchronized void releaseJavaRunThread(JavaRun run) {
LangUtil.throwIaxIfNull(run, "run");
runThread = null;
}
/** @throws ExitCalledException if called from the JavaRun-set thread */
@Override
public void checkExit(int exitCode) throws ExitCalledException {
if ((null != runThread) && runThread.equals(Thread.currentThread())) {
throw new ExitCalledException(exitCode);
}
}
public void checkAwtEventQueueAccess() {
if ((null != runThread) && runThread.equals(Thread.currentThread())) {
throw new AwtUsedException();
}
}
public void checkSystemClipboardAccess() {
// permit
}
// used by constrained calls
public static class ExitCalledException extends SecurityException {
public final int exitCode;
public ExitCalledException(int exitCode) {
this.exitCode = exitCode;
}
}
public static class AwtUsedException extends SecurityException {
public AwtUsedException() { }
}
// permit everything else
@Override
public void checkAccept(String arg0, int arg1) {
}
@Override
public void checkAccess(Thread arg0) {
}
@Override
public void checkAccess(ThreadGroup arg0) {
}
@Override
public void checkConnect(String arg0, int arg1) {
}
@Override
public void checkConnect(String arg0, int arg1, Object arg2) {
}
@Override
public void checkCreateClassLoader() {
}
@Override
public void checkDelete(String arg0) {
}
@Override
public void checkExec(String arg0) {
}
@Override
public void checkLink(String arg0) {
}
@Override
public void checkListen(int arg0) {
}
public void checkMemberAccess(Class arg0, int arg1) {
}
@Override
public void checkMulticast(InetAddress arg0) {
}
@Override
public void checkMulticast(InetAddress arg0, byte arg1) {
}
@Override
public void checkPackageAccess(String arg0) {
}
@Override
public void checkPackageDefinition(String arg0) {
}
@Override
public void checkPermission(Permission arg0) {
}
@Override
public void checkPermission(Permission arg0, Object arg1) {
}
@Override
public void checkPrintJobAccess() {
}
@Override
public void checkPropertiesAccess() {
}
@Override
public void checkPropertyAccess(String arg0) {
}
@Override
public void checkRead(FileDescriptor arg0) {
}
@Override
public void checkRead(String arg0) {
}
@Override
public void checkRead(String arg0, Object arg1) {
}
@Override
public void checkSecurityAccess(String arg0) {
}
@Override
public void checkSetFactory() {
}
public boolean checkTopLevelWindow(Object arg0) {
return true;
}
@Override
public void checkWrite(FileDescriptor arg0) {
}
@Override
public void checkWrite(String arg0) {
}
}
}