source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/Java.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

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