1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 package org.apache.tools.ant.taskdefs;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.PrintWriter;
24 import java.io.StringWriter;
25 import java.util.Vector;
26 import org.apache.tools.ant.BuildException;
27 import org.apache.tools.ant.ExitException;
28 import org.apache.tools.ant.Project;
29 import org.apache.tools.ant.Task;
30 import org.apache.tools.ant.ExitStatusException;
31 import org.apache.tools.ant.types.Commandline;
32 import org.apache.tools.ant.types.CommandlineJava;
33 import org.apache.tools.ant.types.Environment;
34 import org.apache.tools.ant.types.Path;
35 import org.apache.tools.ant.types.PropertySet;
36 import org.apache.tools.ant.types.Reference;
37 import org.apache.tools.ant.types.Assertions;
38 import org.apache.tools.ant.types.Permissions;
39 import org.apache.tools.ant.types.RedirectorElement;
40 import org.apache.tools.ant.taskdefs.condition.Os;
41 import org.apache.tools.ant.util.KeepAliveInputStream;
42
43 /**
44 * Launcher for Java applications. Allows use of
45 * the same JVM for the called application thus resulting in much
46 * faster operation.
47 *
48 * @since Ant 1.1
49 *
50 * @ant.task category="java"
51 */
52 public class Java extends Task {
53
54 private CommandlineJava cmdl = new CommandlineJava();
55 private Environment env = new Environment();
56 private boolean fork = false;
57 private boolean newEnvironment = false;
58 private File dir = null;
59 private boolean failOnError = false;
60 private Long timeout = null;
61
62 //include locally for screening purposes
63 private String inputString;
64 private File input;
65 private File output;
66 private File error;
67
68 // CheckStyle:VisibilityModifier OFF - bc
69 protected Redirector redirector = new Redirector(this);
70 protected RedirectorElement redirectorElement;
71 // CheckStyle:VisibilityModifier ON
72
73 private String resultProperty;
74 private Permissions perm = null;
75
76 private boolean spawn = false;
77 private boolean incompatibleWithSpawn = false;
78
79 /**
80 * Normal constructor
81 */
82 public Java() {
83 }
84
85 /**
86 * create a bound task
87 * @param owner owner
88 */
89 public Java(Task owner) {
90 bindToOwner(owner);
91 }
92
93 /**
94 * Do the execution.
95 * @throws BuildException if failOnError is set to true and the application
96 * returns a nonzero result code.
97 */
98 public void execute() throws BuildException {
99 File savedDir = dir;
100 Permissions savedPermissions = perm;
101
102 int err = -1;
103 try {
104 checkConfiguration();
105 err = executeJava();
106 if (err != 0) {
107 if (failOnError) {
108 throw new ExitStatusException("Java returned: " + err,
109 err,
110 getLocation());
111 } else {
112 log("Java Result: " + err, Project.MSG_ERR);
113 }
114 }
115 maybeSetResultPropertyValue(err);
116 } finally {
117 dir = savedDir;
118 perm = savedPermissions;
119 }
120 }
121
122 /**
123 * Do the execution and return a return code.
124 *
125 * @return the return code from the execute java class if it was
126 * executed in a separate VM (fork = "yes") or a security manager was
127 * installed that prohibits ExitVM (default).
128 *
129 * @throws BuildException if required parameters are missing.
130 */
131 public int executeJava() throws BuildException {
132 return executeJava(getCommandLine());
133 }
134
135 /**
136 * Check configuration.
137 * @throws BuildException if required parameters are missing.
138 */
139 protected void checkConfiguration() throws BuildException {
140 String classname = getCommandLine().getClassname();
141 if (classname == null && getCommandLine().getJar() == null) {
142 throw new BuildException("Classname must not be null.");
143 }
144 if (!fork && getCommandLine().getJar() != null) {
145 throw new BuildException("Cannot execute a jar in non-forked mode."
146 + " Please set fork='true'. ");
147 }
148 if (spawn && !fork) {
149 throw new BuildException("Cannot spawn a java process in non-forked mode."
150 + " Please set fork='true'. ");
151 }
152 if (getCommandLine().getClasspath() != null
153 && getCommandLine().getJar() != null) {
154 log("When using 'jar' attribute classpath-settings are ignored. "
155 + "See the manual for more information.", Project.MSG_VERBOSE);
156 }
157 if (spawn && incompatibleWithSpawn) {
158 getProject().log("spawn does not allow attributes related to input, "
159 + "output, error, result", Project.MSG_ERR);
160 getProject().log("spawn also does not allow timeout", Project.MSG_ERR);
161 getProject().log("finally, spawn is not compatible "
162 + "with a nested I/O <redirector>", Project.MSG_ERR);
163 throw new BuildException("You have used an attribute "
164 + "or nested element which is not compatible with spawn");
165 }
166 if (getCommandLine().getAssertions() != null && !fork) {
167 log("Assertion statements are currently ignored in non-forked mode");
168 }
169 if (fork) {
170 if (perm != null) {
171 log("Permissions can not be set this way in forked mode.", Project.MSG_WARN);
172 }
173 log(getCommandLine().describeCommand(), Project.MSG_VERBOSE);
174 } else {
175 if (getCommandLine().getVmCommand().size() > 1) {
176 log("JVM args ignored when same JVM is used.",
177 Project.MSG_WARN);
178 }
179 if (dir != null) {
180 log("Working directory ignored when same JVM is used.",
181 Project.MSG_WARN);
182 }
183 if (newEnvironment || null != env.getVariables()) {
184 log("Changes to environment variables are ignored when same "
185 + "JVM is used.", Project.MSG_WARN);
186 }
187 if (getCommandLine().getBootclasspath() != null) {
188 log("bootclasspath ignored when same JVM is used.",
189 Project.MSG_WARN);
190 }
191 if (perm == null) {
192 perm = new Permissions(true);
193 log("running " + this.getCommandLine().getClassname()
194 + " with default permissions (exit forbidden)", Project.MSG_VERBOSE);
195 }
196 log("Running in same VM " + getCommandLine().describeJavaCommand(),
197 Project.MSG_VERBOSE);
198 }
199 setupRedirector();
200 }
201
202 /**
203 * Execute the specified CommandlineJava.
204 * @param commandLine CommandLineJava instance.
205 * @return the exit value of the process if forked, 0 otherwise.
206 */
207 protected int executeJava(CommandlineJava commandLine) {
208 try {
209 if (fork) {
210 if (!spawn) {
211 return fork(commandLine.getCommandline());
212 } else {
213 spawn(commandLine.getCommandline());
214 return 0;
215 }
216 } else {
217 try {
218 run(commandLine);
219 return 0;
220 } catch (ExitException ex) {
221 return ex.getStatus();
222 }
223 }
224 } catch (BuildException e) {
225 if (e.getLocation() == null && getLocation() != null) {
226 e.setLocation(getLocation());
227 }
228 if (failOnError) {
229 throw e;
230 } else {
231 log(e);
232 return -1;
233 }
234 } catch (ThreadDeath t) {
235 throw t; // cf. NB #47191
236 } catch (Throwable t) {
237 if (failOnError) {
238 throw new BuildException(t, getLocation());
239 } else {
240 log(t);
241 return -1;
242 }
243 }
244 }
245
246 /**
247 * Set whether or not you want the process to be spawned;
248 * default is not spawned.
249 * @param spawn if true you do not want Ant to wait for the end of the process.
250 * @since Ant 1.6
251 */
252 public void setSpawn(boolean spawn) {
253 this.spawn = spawn;
254 }
255
256 /**
257 * Set the classpath to be used when running the Java class.
258 *
259 * @param s an Ant Path object containing the classpath.
260 */
261 public void setClasspath(Path s) {
262 createClasspath().append(s);
263 }
264
265 /**
266 * Add a path to the classpath.
267 *
268 * @return created classpath.
269 */
270 public Path createClasspath() {
271 return getCommandLine().createClasspath(getProject()).createPath();
272 }
273
274 /**
275 * Add a path to the bootclasspath.
276 * @since Ant 1.6
277 *
278 * @return created bootclasspath.
279 */
280 public Path createBootclasspath() {
281 return getCommandLine().createBootclasspath(getProject()).createPath();
282 }
283
284 /**
285 * Set the permissions for the application run inside the same JVM.
286 * @since Ant 1.6
287 * @return Permissions.
288 */
289 public Permissions createPermissions() {
290 perm = (perm == null) ? new Permissions() : perm;
291 return perm;
292 }
293
294 /**
295 * Set the classpath to use by reference.
296 *
297 * @param r a reference to an existing classpath.
298 */
299 public void setClasspathRef(Reference r) {
300 createClasspath().setRefid(r);
301 }
302
303 /**
304 * Set the location of the JAR file to execute.
305 *
306 * @param jarfile the jarfile to execute.
307 *
308 * @throws BuildException if there is also a main class specified.
309 */
310 public void setJar(File jarfile) throws BuildException {
311 if (getCommandLine().getClassname() != null) {
312 throw new BuildException("Cannot use 'jar' and 'classname' "
313 + "attributes in same command.");
314 }
315 getCommandLine().setJar(jarfile.getAbsolutePath());
316 }
317
318 /**
319 * Set the Java class to execute.
320 *
321 * @param s the name of the main class.
322 *
323 * @throws BuildException if the jar attribute has been set.
324 */
325 public void setClassname(String s) throws BuildException {
326 if (getCommandLine().getJar() != null) {
327 throw new BuildException("Cannot use 'jar' and 'classname' "
328 + "attributes in same command");
329 }
330 getCommandLine().setClassname(s);
331 }
332
333 /**
334 * Deprecated: use nested arg instead.
335 * Set the command line arguments for the class.
336 *
337 * @param s arguments.
338 *
339 * @ant.attribute ignore="true"
340 */
341 public void setArgs(String s) {
342 log("The args attribute is deprecated. "
343 + "Please use nested arg elements.", Project.MSG_WARN);
344 getCommandLine().createArgument().setLine(s);
345 }
346
347 /**
348 * If set, system properties will be copied to the cloned VM--as
349 * well as the bootclasspath unless you have explicitly specified
350 * a bootclaspath.
351 *
352 * <p>Doesn't have any effect unless fork is true.</p>
353 * @param cloneVm if true copy system properties.
354 * @since Ant 1.7
355 */
356 public void setCloneVm(boolean cloneVm) {
357 getCommandLine().setCloneVm(cloneVm);
358 }
359
360 /**
361 * Add a command-line argument.
362 *
363 * @return created argument.
364 */
365 public Commandline.Argument createArg() {
366 return getCommandLine().createArgument();
367 }
368
369 /**
370 * Set the name of the property in which the return code of the
371 * command should be stored. Only of interest if failonerror=false.
372 *
373 * @param resultProperty name of property.
374 *
375 * @since Ant 1.6
376 */
377 public void setResultProperty(String resultProperty) {
378 this.resultProperty = resultProperty;
379 incompatibleWithSpawn = true;
380 }
381
382 /**
383 * Helper method to set result property to the
384 * passed in value if appropriate.
385 *
386 * @param result the exit code
387 */
388 protected void maybeSetResultPropertyValue(int result) {
389 String res = Integer.toString(result);
390 if (resultProperty != null) {
391 getProject().setNewProperty(resultProperty, res);
392 }
393 }
394
395 /**
396 * If true, execute in a new VM.
397 *
398 * @param s do you want to run Java in a new VM.
399 */
400 public void setFork(boolean s) {
401 this.fork = s;
402 }
403
404 /**
405 * Set the command line arguments for the JVM.
406 *
407 * @param s jvmargs.
408 */
409 public void setJvmargs(String s) {
410 log("The jvmargs attribute is deprecated. "
411 + "Please use nested jvmarg elements.", Project.MSG_WARN);
412 getCommandLine().createVmArgument().setLine(s);
413 }
414
415 /**
416 * Adds a JVM argument.
417 *
418 * @return JVM argument created.
419 */
420 public Commandline.Argument createJvmarg() {
421 return getCommandLine().createVmArgument();
422 }
423
424 /**
425 * Set the command used to start the VM (only if forking).
426 *
427 * @param s command to start the VM.
428 */
429 public void setJvm(String s) {
430 getCommandLine().setVm(s);
431 }
432
433 /**
434 * Add a system property.
435 *
436 * @param sysp system property.
437 */
438 public void addSysproperty(Environment.Variable sysp) {
439 getCommandLine().addSysproperty(sysp);
440 }
441
442 /**
443 * Add a set of properties as system properties.
444 *
445 * @param sysp set of properties to add.
446 *
447 * @since Ant 1.6
448 */
449 public void addSyspropertyset(PropertySet sysp) {
450 getCommandLine().addSyspropertyset(sysp);
451 }
452
453 /**
454 * If true, then fail if the command exits with a
455 * returncode other than zero.
456 *
457 * @param fail if true fail the build when the command exits with a
458 * nonzero returncode.
459 */
460 public void setFailonerror(boolean fail) {
461 failOnError = fail;
462 incompatibleWithSpawn |= fail;
463 }
464
465 /**
466 * Set the working directory of the process.
467 *
468 * @param d working directory.
469 *
470 */
471 public void setDir(File d) {
472 this.dir = d;
473 }
474
475 /**
476 * Set the File to which the output of the process is redirected.
477 *
478 * @param out the output File.
479 */
480 public void setOutput(File out) {
481 this.output = out;
482 incompatibleWithSpawn = true;
483 }
484
485 /**
486 * Set the input to use for the task.
487 *
488 * @param input name of the input file.
489 */
490 public void setInput(File input) {
491 if (inputString != null) {
492 throw new BuildException("The \"input\" and \"inputstring\" "
493 + "attributes cannot both be specified");
494 }
495 this.input = input;
496 incompatibleWithSpawn = true;
497 }
498
499 /**
500 * Set the string to use as input.
501 *
502 * @param inputString the string which is used as the input source.
503 */
504 public void setInputString(String inputString) {
505 if (input != null) {
506 throw new BuildException("The \"input\" and \"inputstring\" "
507 + "attributes cannot both be specified");
508 }
509 this.inputString = inputString;
510 incompatibleWithSpawn = true;
511 }
512
513 /**
514 * Set whether error output of exec is logged. This is only useful
515 * when output is being redirected and error output is desired in the
516 * Ant log.
517 *
518 * @param logError get in the ant log the messages coming from stderr
519 * in the case that fork = true.
520 */
521 public void setLogError(boolean logError) {
522 redirector.setLogError(logError);
523 incompatibleWithSpawn |= logError;
524 }
525
526 /**
527 * Set the File to which the error stream of the process is redirected.
528 *
529 * @param error file getting the error stream.
530 *
531 * @since Ant 1.6
532 */
533 public void setError(File error) {
534 this.error = error;
535 incompatibleWithSpawn = true;
536 }
537
538 /**
539 * Set the property name whose value should be set to the output of
540 * the process.
541 *
542 * @param outputProp property name.
543 *
544 */
545 public void setOutputproperty(String outputProp) {
546 redirector.setOutputProperty(outputProp);
547 incompatibleWithSpawn = true;
548 }
549
550 /**
551 * Set the property name whose value should be set to the error of
552 * the process.
553 *
554 * @param errorProperty property name.
555 *
556 * @since Ant 1.6
557 */
558 public void setErrorProperty(String errorProperty) {
559 redirector.setErrorProperty(errorProperty);
560 incompatibleWithSpawn = true;
561 }
562
563 /**
564 * Corresponds to -mx or -Xmx depending on VM version.
565 *
566 * @param max max memory parameter.
567 */
568 public void setMaxmemory(String max) {
569 getCommandLine().setMaxmemory(max);
570 }
571
572 /**
573 * Set the JVM version.
574 * @param value JVM version.
575 */
576 public void setJVMVersion(String value) {
577 getCommandLine().setVmversion(value);
578 }
579
580 /**
581 * Add an environment variable.
582 *
583 * <p>Will be ignored if we are not forking a new VM.
584 *
585 * @param var new environment variable.
586 *
587 * @since Ant 1.5
588 */
589 public void addEnv(Environment.Variable var) {
590 env.addVariable(var);
591 }
592
593 /**
594 * If true, use a completely new environment.
595 *
596 * <p>Will be ignored if we are not forking a new VM.
597 *
598 * @param newenv if true, use a completely new environment.
599 *
600 * @since Ant 1.5
601 */
602 public void setNewenvironment(boolean newenv) {
603 newEnvironment = newenv;
604 }
605
606 /**
607 * If true, append output to existing file.
608 *
609 * @param append if true, append output to existing file.
610 *
611 * @since Ant 1.5
612 */
613 public void setAppend(boolean append) {
614 redirector.setAppend(append);
615 incompatibleWithSpawn = true;
616 }
617
618 /**
619 * Set the timeout in milliseconds after which the process will be killed.
620 *
621 * @param value timeout in milliseconds.
622 *
623 * @since Ant 1.5
624 */
625 public void setTimeout(Long value) {
626 timeout = value;
627 incompatibleWithSpawn |= timeout != null;
628 }
629
630 /**
631 * Add assertions to enable in this program (if fork=true).
632 * @param asserts assertion set.
633 * @since Ant 1.6
634 */
635 public void addAssertions(Assertions asserts) {
636 if (getCommandLine().getAssertions() != null) {
637 throw new BuildException("Only one assertion declaration is allowed");
638 }
639 getCommandLine().setAssertions(asserts);
640 }
641
642 /**
643 * Add a <code>RedirectorElement</code> to this task.
644 * @param redirectorElement <code>RedirectorElement</code>.
645 */
646 public void addConfiguredRedirector(RedirectorElement redirectorElement) {
647 if (this.redirectorElement != null) {
648 throw new BuildException("cannot have > 1 nested redirectors");
649 }
650 this.redirectorElement = redirectorElement;
651 incompatibleWithSpawn = true;
652 }
653
654 /**
655 * Pass output sent to System.out to specified output file.
656 *
657 * @param output a string of output on its way to the handlers.
658 *
659 * @since Ant 1.5
660 */
661 protected void handleOutput(String output) {
662 if (redirector.getOutputStream() != null) {
663 redirector.handleOutput(output);
664 } else {
665 super.handleOutput(output);
666 }
667 }
668
669 /**
670 * Handle an input request by this task.
671 *
672 * @param buffer the buffer into which data is to be read.
673 * @param offset the offset into the buffer at which data is stored.
674 * @param length the amount of data to read.
675 *
676 * @return the number of bytes read.
677 *
678 * @exception IOException if the data cannot be read.
679 * @since Ant 1.6
680 */
681 public int handleInput(byte[] buffer, int offset, int length)
682 throws IOException {
683 // Should work whether or not redirector.inputStream == null:
684 return redirector.handleInput(buffer, offset, length);
685 }
686
687 /**
688 * Pass output sent to System.out to specified output file.
689 *
690 * @param output string of output on its way to its handlers.
691 *
692 * @since Ant 1.5.2
693 */
694 protected void handleFlush(String output) {
695 if (redirector.getOutputStream() != null) {
696 redirector.handleFlush(output);
697 } else {
698 super.handleFlush(output);
699 }
700 }
701
702 /**
703 * Handle output sent to System.err.
704 *
705 * @param output string of stderr.
706 *
707 * @since Ant 1.5
708 */
709 protected void handleErrorOutput(String output) {
710 if (redirector.getErrorStream() != null) {
711 redirector.handleErrorOutput(output);
712 } else {
713 super.handleErrorOutput(output);
714 }
715 }
716
717 /**
718 * Handle output sent to System.err and flush the stream.
719 *
720 * @param output string of stderr.
721 *
722 * @since Ant 1.5.2
723 */
724 protected void handleErrorFlush(String output) {
725 if (redirector.getErrorStream() != null) {
726 redirector.handleErrorFlush(output);
727 } else {
728 super.handleErrorOutput(output);
729 }
730 }
731
732 /**
733 * Set up properties on the redirector that we needed to store locally.
734 */
735 protected void setupRedirector() {
736 redirector.setInput(input);
737 redirector.setInputString(inputString);
738 redirector.setOutput(output);
739 redirector.setError(error);
740 if (redirectorElement != null) {
741 redirectorElement.configure(redirector);
742 }
743 if (!spawn && input == null && inputString == null) {
744 // #24918: send standard input to the process by default.
745 redirector.setInputStream(
746 new KeepAliveInputStream(getProject().getDefaultInputStream()));
747 }
748 }
749
750 /**
751 * Executes the given classname with the given arguments as it
752 * were a command line application.
753 * @param command CommandlineJava.
754 */
755 private void run(CommandlineJava command) throws BuildException {
756 try {
757 ExecuteJava exe = new ExecuteJava();
758 exe.setJavaCommand(command.getJavaCommand());
759 exe.setClasspath(command.getClasspath());
760 exe.setSystemProperties(command.getSystemProperties());
761 exe.setPermissions(perm);
762 exe.setTimeout(timeout);
763 redirector.createStreams();
764 exe.execute(getProject());
765 redirector.complete();
766 if (exe.killedProcess()) {
767 throw new BuildException("Timeout: killed the sub-process");
768 }
769 } catch (IOException e) {
770 throw new BuildException(e);
771 }
772 }
773
774 /**
775 * Executes the given classname with the given arguments in a separate VM.
776 * @param command String[] of command-line arguments.
777 */
778 private int fork(String[] command) throws BuildException {
779 Execute exe
780 = new Execute(redirector.createHandler(), createWatchdog());
781 setupExecutable(exe, command);
782
783 try {
784 int rc = exe.execute();
785 redirector.complete();
786 if (exe.killedProcess()) {
787 throw new BuildException("Timeout: killed the sub-process");
788 }
789 return rc;
790 } catch (IOException e) {
791 throw new BuildException(e, getLocation());
792 }
793 }
794
795 /**
796 * Executes the given classname with the given arguments in a separate VM.
797 * @param command String[] of command-line arguments.
798 */
799 private void spawn(String[] command) throws BuildException {
800 Execute exe = new Execute();
801 setupExecutable(exe, command);
802 try {
803 exe.spawn();
804 } catch (IOException e) {
805 throw new BuildException(e, getLocation());
806 }
807 }
808
809 /**
810 * Do all configuration for an executable that
811 * is common across the {@link #fork(String[])} and
812 * {@link #spawn(String[])} methods.
813 * @param exe executable.
814 * @param command command to execute.
815 */
816 private void setupExecutable(Execute exe, String[] command) {
817 exe.setAntRun(getProject());
818 setupWorkingDir(exe);
819 setupEnvironment(exe);
820 setupCommandLine(exe, command);
821 }
822
823 /**
824 * Set up our environment variables.
825 * @param exe executable.
826 */
827 private void setupEnvironment(Execute exe) {
828 String[] environment = env.getVariables();
829 if (environment != null) {
830 for (int i = 0; i < environment.length; i++) {
831 log("Setting environment variable: " + environment[i],
832 Project.MSG_VERBOSE);
833 }
834 }
835 exe.setNewenvironment(newEnvironment);
836 exe.setEnvironment(environment);
837 }
838
839 /**
840 * Set the working dir of the new process.
841 * @param exe executable.
842 * @throws BuildException if the dir doesn't exist.
843 */
844 private void setupWorkingDir(Execute exe) {
845 if (dir == null) {
846 dir = getProject().getBaseDir();
847 } else if (!dir.exists() || !dir.isDirectory()) {
848 throw new BuildException(dir.getAbsolutePath()
849 + " is not a valid directory",
850 getLocation());
851 }
852 exe.setWorkingDirectory(dir);
853 }
854
855 /**
856 * Set the command line for the exe.
857 * On VMS, hands off to {@link #setupCommandLineForVMS(Execute, String[])}.
858 * @param exe executable.
859 * @param command command to execute.
860 */
861 private void setupCommandLine(Execute exe, String[] command) {
862 //On VMS platform, we need to create a special java options file
863 //containing the arguments and classpath for the java command.
864 //The special file is supported by the "-V" switch on the VMS JVM.
865 if (Os.isFamily("openvms")) {
866 setupCommandLineForVMS(exe, command);
867 } else {
868 exe.setCommandline(command);
869 }
870 }
871
872 /**
873 * On VMS platform, we need to create a special java options file
874 * containing the arguments and classpath for the java command.
875 * The special file is supported by the "-V" switch on the VMS JVM.
876 *
877 * @param exe executable.
878 * @param command command to execute.
879 */
880 private void setupCommandLineForVMS(Execute exe, String[] command) {
881 ExecuteJava.setupCommandLineForVMS(exe, command);
882 }
883
884 /**
885 * Executes the given classname with the given arguments as if it
886 * were a command line application.
887 *
888 * @param classname the name of the class to run.
889 * @param args arguments for the class.
890 * @throws BuildException in case of IOException in the execution.
891 */
892 protected void run(String classname, Vector args) throws BuildException {
893 CommandlineJava cmdj = new CommandlineJava();
894 cmdj.setClassname(classname);
895 for (int i = 0; i < args.size(); i++) {
896 cmdj.createArgument().setValue((String) args.elementAt(i));
897 }
898 run(cmdj);
899 }
900
901 /**
902 * Clear out the arguments to this java task.
903 */
904 public void clearArgs() {
905 getCommandLine().clearJavaArgs();
906 }
907
908 /**
909 * Create the Watchdog to kill a runaway process.
910 *
911 * @return new watchdog.
912 *
913 * @throws BuildException under unknown circumstances.
914 *
915 * @since Ant 1.5
916 */
917 protected ExecuteWatchdog createWatchdog() throws BuildException {
918 if (timeout == null) {
919 return null;
920 }
921 return new ExecuteWatchdog(timeout.longValue());
922 }
923
924 /**
925 * Log the specified Throwable.
926 * @param t the Throwable to log.
927 * @since 1.6.2
928 */
929 private void log(Throwable t) {
930 StringWriter sw = new StringWriter();
931 PrintWriter w = new PrintWriter(sw);
932 t.printStackTrace(w);
933 w.close();
934 log(sw.toString(), Project.MSG_ERR);
935 }
936
937 /**
938 * Accessor to the command line.
939 *
940 * @return the current command line.
941 * @since 1.6.3
942 */
943 public CommandlineJava getCommandLine() {
944 return cmdl;
945 }
946
947 /**
948 * Get the system properties of the command line.
949 *
950 * @return the current properties of this java invocation.
951 * @since 1.6.3
952 */
953 public CommandlineJava.SysProperties getSysProperties() {
954 return getCommandLine().getSystemProperties();
955 }
956 }