diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Java.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Java.java | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Java.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Java.java new file mode 100644 index 00000000..5e065bc3 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -0,0 +1,965 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant.taskdefs; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ExitException; +import org.apache.tools.ant.ExitStatusException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.Assertions; +import org.apache.tools.ant.types.Commandline; +import org.apache.tools.ant.types.CommandlineJava; +import org.apache.tools.ant.types.Environment; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Permissions; +import org.apache.tools.ant.types.PropertySet; +import org.apache.tools.ant.types.RedirectorElement; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.util.KeepAliveInputStream; + +/** + * Launcher for Java applications. Allows use of + * the same JVM for the called application thus resulting in much + * faster operation. + * + * @since Ant 1.1 + * + * @ant.task category="java" + */ +public class Java extends Task { + + private CommandlineJava cmdl = new CommandlineJava(); + private Environment env = new Environment(); + private boolean fork = false; + private boolean newEnvironment = false; + private File dir = null; + private boolean failOnError = false; + private Long timeout = null; + + //include locally for screening purposes + private String inputString; + private File input; + private File output; + private File error; + + // CheckStyle:VisibilityModifier OFF - bc + protected Redirector redirector = new Redirector(this); + protected RedirectorElement redirectorElement; + // CheckStyle:VisibilityModifier ON + + private String resultProperty; + private Permissions perm = null; + + private boolean spawn = false; + private boolean incompatibleWithSpawn = false; + + private static final String TIMEOUT_MESSAGE = + "Timeout: killed the sub-process"; + + /** + * Normal constructor + */ + public Java() { + } + + /** + * create a bound task + * @param owner owner + */ + public Java(Task owner) { + bindToOwner(owner); + } + + /** + * Do the execution. + * @throws BuildException if failOnError is set to true and the application + * returns a nonzero result code. + */ + public void execute() throws BuildException { + File savedDir = dir; + Permissions savedPermissions = perm; + + int err = -1; + try { + checkConfiguration(); + err = executeJava(); + if (err != 0) { + if (failOnError) { + throw new ExitStatusException("Java returned: " + err, + err, + getLocation()); + } else { + log("Java Result: " + err, Project.MSG_ERR); + } + } + maybeSetResultPropertyValue(err); + } finally { + dir = savedDir; + perm = savedPermissions; + } + } + + /** + * Do the execution and return a return code. + * + * @return the return code from the execute java class if it was + * executed in a separate VM (fork = "yes") or a security manager was + * installed that prohibits ExitVM (default). + * + * @throws BuildException if required parameters are missing. + */ + public int executeJava() throws BuildException { + return executeJava(getCommandLine()); + } + + /** + * Check configuration. + * @throws BuildException if required parameters are missing. + */ + protected void checkConfiguration() throws BuildException { + String classname = getCommandLine().getClassname(); + if (classname == null && getCommandLine().getJar() == null) { + throw new BuildException("Classname must not be null."); + } + if (!fork && getCommandLine().getJar() != null) { + throw new BuildException("Cannot execute a jar in non-forked mode." + + " Please set fork='true'. "); + } + if (spawn && !fork) { + throw new BuildException("Cannot spawn a java process in non-forked mode." + + " Please set fork='true'. "); + } + if (getCommandLine().getClasspath() != null + && getCommandLine().getJar() != null) { + log("When using 'jar' attribute classpath-settings are ignored. " + + "See the manual for more information.", Project.MSG_VERBOSE); + } + if (spawn && incompatibleWithSpawn) { + getProject().log("spawn does not allow attributes related to input, " + + "output, error, result", Project.MSG_ERR); + getProject().log("spawn also does not allow timeout", Project.MSG_ERR); + getProject().log("finally, spawn is not compatible " + + "with a nested I/O <redirector>", Project.MSG_ERR); + throw new BuildException("You have used an attribute " + + "or nested element which is not compatible with spawn"); + } + if (getCommandLine().getAssertions() != null && !fork) { + log("Assertion statements are currently ignored in non-forked mode"); + } + if (fork) { + if (perm != null) { + log("Permissions can not be set this way in forked mode.", Project.MSG_WARN); + } + log(getCommandLine().describeCommand(), Project.MSG_VERBOSE); + } else { + if (getCommandLine().getVmCommand().size() > 1) { + log("JVM args ignored when same JVM is used.", + Project.MSG_WARN); + } + if (dir != null) { + log("Working directory ignored when same JVM is used.", + Project.MSG_WARN); + } + if (newEnvironment || null != env.getVariables()) { + log("Changes to environment variables are ignored when same " + + "JVM is used.", Project.MSG_WARN); + } + if (getCommandLine().getBootclasspath() != null) { + log("bootclasspath ignored when same JVM is used.", + Project.MSG_WARN); + } + if (perm == null) { + perm = new Permissions(true); + log("running " + this.getCommandLine().getClassname() + + " with default permissions (exit forbidden)", Project.MSG_VERBOSE); + } + log("Running in same VM " + getCommandLine().describeJavaCommand(), + Project.MSG_VERBOSE); + } + setupRedirector(); + } + + /** + * Execute the specified CommandlineJava. + * @param commandLine CommandLineJava instance. + * @return the exit value of the process if forked, 0 otherwise. + */ + protected int executeJava(CommandlineJava commandLine) { + try { + if (fork) { + if (!spawn) { + return fork(commandLine.getCommandline()); + } else { + spawn(commandLine.getCommandline()); + return 0; + } + } else { + try { + run(commandLine); + return 0; + } catch (ExitException ex) { + return ex.getStatus(); + } + } + } catch (BuildException e) { + if (e.getLocation() == null && getLocation() != null) { + e.setLocation(getLocation()); + } + if (failOnError) { + throw e; + } else { + if (TIMEOUT_MESSAGE.equals(e.getMessage())) { + log(TIMEOUT_MESSAGE); + } else { + log(e); + } + return -1; + } + } catch (ThreadDeath t) { + throw t; // cf. NB #47191 + } catch (Throwable t) { + if (failOnError) { + throw new BuildException(t, getLocation()); + } else { + log(t); + return -1; + } + } + } + + /** + * Set whether or not you want the process to be spawned; + * default is not spawned. + * @param spawn if true you do not want Ant to wait for the end of the process. + * @since Ant 1.6 + */ + public void setSpawn(boolean spawn) { + this.spawn = spawn; + } + + /** + * Set the classpath to be used when running the Java class. + * + * @param s an Ant Path object containing the classpath. + */ + public void setClasspath(Path s) { + createClasspath().append(s); + } + + /** + * Add a path to the classpath. + * + * @return created classpath. + */ + public Path createClasspath() { + return getCommandLine().createClasspath(getProject()).createPath(); + } + + /** + * Add a path to the bootclasspath. + * @since Ant 1.6 + * + * @return created bootclasspath. + */ + public Path createBootclasspath() { + return getCommandLine().createBootclasspath(getProject()).createPath(); + } + + /** + * Set the permissions for the application run inside the same JVM. + * @since Ant 1.6 + * @return Permissions. + */ + public Permissions createPermissions() { + perm = (perm == null) ? new Permissions() : perm; + return perm; + } + + /** + * Set the classpath to use by reference. + * + * @param r a reference to an existing classpath. + */ + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + /** + * Set the location of the JAR file to execute. + * + * @param jarfile the jarfile to execute. + * + * @throws BuildException if there is also a main class specified. + */ + public void setJar(File jarfile) throws BuildException { + if (getCommandLine().getClassname() != null) { + throw new BuildException("Cannot use 'jar' and 'classname' " + + "attributes in same command."); + } + getCommandLine().setJar(jarfile.getAbsolutePath()); + } + + /** + * Set the Java class to execute. + * + * @param s the name of the main class. + * + * @throws BuildException if the jar attribute has been set. + */ + public void setClassname(String s) throws BuildException { + if (getCommandLine().getJar() != null) { + throw new BuildException("Cannot use 'jar' and 'classname' " + + "attributes in same command"); + } + getCommandLine().setClassname(s); + } + + /** + * Deprecated: use nested arg instead. + * Set the command line arguments for the class. + * + * @param s arguments. + * + * @ant.attribute ignore="true" + */ + public void setArgs(String s) { + log("The args attribute is deprecated. " + + "Please use nested arg elements.", Project.MSG_WARN); + getCommandLine().createArgument().setLine(s); + } + + /** + * If set, system properties will be copied to the cloned VM--as + * well as the bootclasspath unless you have explicitly specified + * a bootclasspath. + * + * <p>Doesn't have any effect unless fork is true.</p> + * @param cloneVm if true copy system properties. + * @since Ant 1.7 + */ + public void setCloneVm(boolean cloneVm) { + getCommandLine().setCloneVm(cloneVm); + } + + /** + * Add a command-line argument. + * + * @return created argument. + */ + public Commandline.Argument createArg() { + return getCommandLine().createArgument(); + } + + /** + * Set the name of the property in which the return code of the + * command should be stored. Only of interest if failonerror=false. + * + * @param resultProperty name of property. + * + * @since Ant 1.6 + */ + public void setResultProperty(String resultProperty) { + this.resultProperty = resultProperty; + incompatibleWithSpawn = true; + } + + /** + * Helper method to set result property to the + * passed in value if appropriate. + * + * @param result the exit code + */ + protected void maybeSetResultPropertyValue(int result) { + String res = Integer.toString(result); + if (resultProperty != null) { + getProject().setNewProperty(resultProperty, res); + } + } + + /** + * If true, execute in a new VM. + * + * @param s do you want to run Java in a new VM. + */ + public void setFork(boolean s) { + this.fork = s; + } + + /** + * Set the command line arguments for the JVM. + * + * @param s jvmargs. + */ + public void setJvmargs(String s) { + log("The jvmargs attribute is deprecated. " + + "Please use nested jvmarg elements.", Project.MSG_WARN); + getCommandLine().createVmArgument().setLine(s); + } + + /** + * Adds a JVM argument. + * + * @return JVM argument created. + */ + public Commandline.Argument createJvmarg() { + return getCommandLine().createVmArgument(); + } + + /** + * Set the command used to start the VM (only if forking). + * + * @param s command to start the VM. + */ + public void setJvm(String s) { + getCommandLine().setVm(s); + } + + /** + * Add a system property. + * + * @param sysp system property. + */ + public void addSysproperty(Environment.Variable sysp) { + getCommandLine().addSysproperty(sysp); + } + + /** + * Add a set of properties as system properties. + * + * @param sysp set of properties to add. + * + * @since Ant 1.6 + */ + public void addSyspropertyset(PropertySet sysp) { + getCommandLine().addSyspropertyset(sysp); + } + + /** + * If true, then fail if the command exits with a + * returncode other than zero. + * + * @param fail if true fail the build when the command exits with a + * nonzero returncode. + */ + public void setFailonerror(boolean fail) { + failOnError = fail; + incompatibleWithSpawn |= fail; + } + + /** + * Set the working directory of the process. + * + * @param d working directory. + * + */ + public void setDir(File d) { + this.dir = d; + } + + /** + * Set the File to which the output of the process is redirected. + * + * @param out the output File. + */ + public void setOutput(File out) { + this.output = out; + incompatibleWithSpawn = true; + } + + /** + * Set the input to use for the task. + * + * @param input name of the input file. + */ + public void setInput(File input) { + if (inputString != null) { + throw new BuildException("The \"input\" and \"inputstring\" " + + "attributes cannot both be specified"); + } + this.input = input; + incompatibleWithSpawn = true; + } + + /** + * Set the string to use as input. + * + * @param inputString the string which is used as the input source. + */ + public void setInputString(String inputString) { + if (input != null) { + throw new BuildException("The \"input\" and \"inputstring\" " + + "attributes cannot both be specified"); + } + this.inputString = inputString; + incompatibleWithSpawn = true; + } + + /** + * Set whether error output of exec is logged. This is only useful + * when output is being redirected and error output is desired in the + * Ant log. + * + * @param logError get in the ant log the messages coming from stderr + * in the case that fork = true. + */ + public void setLogError(boolean logError) { + redirector.setLogError(logError); + incompatibleWithSpawn |= logError; + } + + /** + * Set the File to which the error stream of the process is redirected. + * + * @param error file getting the error stream. + * + * @since Ant 1.6 + */ + public void setError(File error) { + this.error = error; + incompatibleWithSpawn = true; + } + + /** + * Set the property name whose value should be set to the output of + * the process. + * + * @param outputProp property name. + * + */ + public void setOutputproperty(String outputProp) { + redirector.setOutputProperty(outputProp); + incompatibleWithSpawn = true; + } + + /** + * Set the property name whose value should be set to the error of + * the process. + * + * @param errorProperty property name. + * + * @since Ant 1.6 + */ + public void setErrorProperty(String errorProperty) { + redirector.setErrorProperty(errorProperty); + incompatibleWithSpawn = true; + } + + /** + * Corresponds to -mx or -Xmx depending on VM version. + * + * @param max max memory parameter. + */ + public void setMaxmemory(String max) { + getCommandLine().setMaxmemory(max); + } + + /** + * Set the JVM version. + * @param value JVM version. + */ + public void setJVMVersion(String value) { + getCommandLine().setVmversion(value); + } + + /** + * Add an environment variable. + * + * <p>Will be ignored if we are not forking a new VM. + * + * @param var new environment variable. + * + * @since Ant 1.5 + */ + public void addEnv(Environment.Variable var) { + env.addVariable(var); + } + + /** + * If true, use a completely new environment. + * + * <p>Will be ignored if we are not forking a new VM. + * + * @param newenv if true, use a completely new environment. + * + * @since Ant 1.5 + */ + public void setNewenvironment(boolean newenv) { + newEnvironment = newenv; + } + + /** + * If true, append output to existing file. + * + * @param append if true, append output to existing file. + * + * @since Ant 1.5 + */ + public void setAppend(boolean append) { + redirector.setAppend(append); + incompatibleWithSpawn |= append; + } + + /** + * Set the timeout in milliseconds after which the process will be killed. + * + * @param value timeout in milliseconds. + * + * @since Ant 1.5 + */ + public void setTimeout(Long value) { + timeout = value; + incompatibleWithSpawn |= timeout != null; + } + + /** + * Add assertions to enable in this program (if fork=true). + * @param asserts assertion set. + * @since Ant 1.6 + */ + public void addAssertions(Assertions asserts) { + if (getCommandLine().getAssertions() != null) { + throw new BuildException("Only one assertion declaration is allowed"); + } + getCommandLine().setAssertions(asserts); + } + + /** + * Add a <code>RedirectorElement</code> to this task. + * @param redirectorElement <code>RedirectorElement</code>. + */ + public void addConfiguredRedirector(RedirectorElement redirectorElement) { + if (this.redirectorElement != null) { + throw new BuildException("cannot have > 1 nested redirectors"); + } + this.redirectorElement = redirectorElement; + incompatibleWithSpawn = true; + } + + /** + * Pass output sent to System.out to specified output file. + * + * @param output a string of output on its way to the handlers. + * + * @since Ant 1.5 + */ + protected void handleOutput(String output) { + if (redirector.getOutputStream() != null) { + redirector.handleOutput(output); + } else { + super.handleOutput(output); + } + } + + /** + * Handle an input request by this task. + * + * @param buffer the buffer into which data is to be read. + * @param offset the offset into the buffer at which data is stored. + * @param length the amount of data to read. + * + * @return the number of bytes read. + * + * @exception IOException if the data cannot be read. + * @since Ant 1.6 + */ + public int handleInput(byte[] buffer, int offset, int length) + throws IOException { + // Should work whether or not redirector.inputStream == null: + return redirector.handleInput(buffer, offset, length); + } + + /** + * Pass output sent to System.out to specified output file. + * + * @param output string of output on its way to its handlers. + * + * @since Ant 1.5.2 + */ + protected void handleFlush(String output) { + if (redirector.getOutputStream() != null) { + redirector.handleFlush(output); + } else { + super.handleFlush(output); + } + } + + /** + * Handle output sent to System.err. + * + * @param output string of stderr. + * + * @since Ant 1.5 + */ + protected void handleErrorOutput(String output) { + if (redirector.getErrorStream() != null) { + redirector.handleErrorOutput(output); + } else { + super.handleErrorOutput(output); + } + } + + /** + * Handle output sent to System.err and flush the stream. + * + * @param output string of stderr. + * + * @since Ant 1.5.2 + */ + protected void handleErrorFlush(String output) { + if (redirector.getErrorStream() != null) { + redirector.handleErrorFlush(output); + } else { + super.handleErrorFlush(output); + } + } + + /** + * Set up properties on the redirector that we needed to store locally. + */ + protected void setupRedirector() { + redirector.setInput(input); + redirector.setInputString(inputString); + redirector.setOutput(output); + redirector.setError(error); + if (redirectorElement != null) { + redirectorElement.configure(redirector); + } + if (!spawn && input == null && inputString == null) { + // #24918: send standard input to the process by default. + redirector.setInputStream( + new KeepAliveInputStream(getProject().getDefaultInputStream())); + } + } + + /** + * Executes the given classname with the given arguments as it + * were a command line application. + * @param command CommandlineJava. + */ + private void run(CommandlineJava command) throws BuildException { + try { + ExecuteJava exe = new ExecuteJava(); + exe.setJavaCommand(command.getJavaCommand()); + exe.setClasspath(command.getClasspath()); + exe.setSystemProperties(command.getSystemProperties()); + exe.setPermissions(perm); + exe.setTimeout(timeout); + redirector.createStreams(); + exe.execute(getProject()); + redirector.complete(); + if (exe.killedProcess()) { + throw new BuildException(TIMEOUT_MESSAGE); + } + } catch (IOException e) { + throw new BuildException(e); + } + } + + /** + * Executes the given classname with the given arguments in a separate VM. + * @param command String[] of command-line arguments. + */ + private int fork(String[] command) throws BuildException { + Execute exe + = new Execute(redirector.createHandler(), createWatchdog()); + setupExecutable(exe, command); + + try { + int rc = exe.execute(); + redirector.complete(); + if (exe.killedProcess()) { + throw new BuildException(TIMEOUT_MESSAGE); + } + return rc; + } catch (IOException e) { + throw new BuildException(e, getLocation()); + } + } + + /** + * Executes the given classname with the given arguments in a separate VM. + * @param command String[] of command-line arguments. + */ + private void spawn(String[] command) throws BuildException { + Execute exe = new Execute(); + setupExecutable(exe, command); + try { + exe.spawn(); + } catch (IOException e) { + throw new BuildException(e, getLocation()); + } + } + + /** + * Do all configuration for an executable that + * is common across the {@link #fork(String[])} and + * {@link #spawn(String[])} methods. + * @param exe executable. + * @param command command to execute. + */ + private void setupExecutable(Execute exe, String[] command) { + exe.setAntRun(getProject()); + setupWorkingDir(exe); + setupEnvironment(exe); + setupCommandLine(exe, command); + } + + /** + * Set up our environment variables. + * @param exe executable. + */ + private void setupEnvironment(Execute exe) { + String[] environment = env.getVariables(); + if (environment != null) { + for (int i = 0; i < environment.length; i++) { + log("Setting environment variable: " + environment[i], + Project.MSG_VERBOSE); + } + } + exe.setNewenvironment(newEnvironment); + exe.setEnvironment(environment); + } + + /** + * Set the working dir of the new process. + * @param exe executable. + * @throws BuildException if the dir doesn't exist. + */ + private void setupWorkingDir(Execute exe) { + if (dir == null) { + dir = getProject().getBaseDir(); + } else if (!dir.exists() || !dir.isDirectory()) { + throw new BuildException(dir.getAbsolutePath() + + " is not a valid directory", + getLocation()); + } + exe.setWorkingDirectory(dir); + } + + /** + * Set the command line for the exe. + * On VMS, hands off to {@link #setupCommandLineForVMS(Execute, String[])}. + * @param exe executable. + * @param command command to execute. + */ + private void setupCommandLine(Execute exe, String[] command) { + //On VMS platform, we need to create a special java options file + //containing the arguments and classpath for the java command. + //The special file is supported by the "-V" switch on the VMS JVM. + if (Os.isFamily("openvms")) { + setupCommandLineForVMS(exe, command); + } else { + exe.setCommandline(command); + } + } + + /** + * On VMS platform, we need to create a special java options file + * containing the arguments and classpath for the java command. + * The special file is supported by the "-V" switch on the VMS JVM. + * + * @param exe executable. + * @param command command to execute. + */ + private void setupCommandLineForVMS(Execute exe, String[] command) { + ExecuteJava.setupCommandLineForVMS(exe, command); + } + + /** + * Executes the given classname with the given arguments as if it + * were a command line application. + * + * @param classname the name of the class to run. + * @param args arguments for the class. + * @throws BuildException in case of IOException in the execution. + */ + protected void run(String classname, Vector<String> args) throws BuildException { + CommandlineJava cmdj = new CommandlineJava(); + cmdj.setClassname(classname); + final int size = args.size(); + for (int i = 0; i < size; i++) { + cmdj.createArgument().setValue(args.elementAt(i)); + } + run(cmdj); + } + + /** + * Clear out the arguments to this java task. + */ + public void clearArgs() { + getCommandLine().clearJavaArgs(); + } + + /** + * Create the Watchdog to kill a runaway process. + * + * @return new watchdog. + * + * @throws BuildException under unknown circumstances. + * + * @since Ant 1.5 + */ + protected ExecuteWatchdog createWatchdog() throws BuildException { + if (timeout == null) { + return null; + } + return new ExecuteWatchdog(timeout.longValue()); + } + + /** + * Log the specified Throwable. + * @param t the Throwable to log. + * @since 1.6.2 + */ + private void log(Throwable t) { + StringWriter sw = new StringWriter(); + PrintWriter w = new PrintWriter(sw); + t.printStackTrace(w); + w.close(); + log(sw.toString(), Project.MSG_ERR); + } + + /** + * Accessor to the command line. + * + * @return the current command line. + * @since 1.6.3 + */ + public CommandlineJava getCommandLine() { + return cmdl; + } + + /** + * Get the system properties of the command line. + * + * @return the current properties of this java invocation. + * @since 1.6.3 + */ + public CommandlineJava.SysProperties getSysProperties() { + return getCommandLine().getSystemProperties(); + } +} |