KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > types > CommandlineJava


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.types;
20
21 import org.apache.tools.ant.BuildException;
22 import org.apache.tools.ant.Project;
23 import org.apache.tools.ant.util.JavaEnvUtils;
24
25 import java.util.Enumeration JavaDoc;
26 import java.util.LinkedList JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.ListIterator JavaDoc;
29 import java.util.Properties JavaDoc;
30 import java.util.Vector JavaDoc;
31
32 /**
33  * A representation of a Java command line that is
34  * a composite of 2 <tt>Commandline</tt>s. One is used for the
35  * vm/options and one for the classname/arguments. It provides
36  * specific methods for a Java command line.
37  *
38  */

39 public class CommandlineJava implements Cloneable JavaDoc {
40
41     /**
42      * commands to the JVM
43      */

44     private Commandline vmCommand = new Commandline();
45     /**
46      * actual java commands
47      */

48     private Commandline javaCommand = new Commandline();
49     /**
50      * properties to add using -D
51      */

52     private SysProperties sysProperties = new SysProperties();
53     private Path classpath = null;
54     private Path bootclasspath = null;
55     private String JavaDoc vmVersion;
56     private String JavaDoc maxMemory = null;
57     /**
58      * any assertions to make? Currently only supported in forked JVMs
59      */

60     private Assertions assertions = null;
61
62     /**
63      * Indicate whether it will execute a jar file or not, in this case
64      * the first vm option must be a -jar and the 'executable' is a jar file.
65      */

66      private boolean executeJar = false;
67
68     /**
69      * Whether system properties and bootclasspath shall be cloned.
70      * @since Ant 1.7
71      */

72     private boolean cloneVm = false;
73
74     /**
75      * Specialized Environment class for System properties.
76      */

77     public static class SysProperties extends Environment implements Cloneable JavaDoc {
78         // CheckStyle:VisibilityModifier OFF - bc
79
/** the system properties. */
80         Properties JavaDoc sys = null;
81         // CheckStyle:VisibilityModifier ON
82
private Vector JavaDoc propertySets = new Vector JavaDoc();
83
84         /**
85          * Get the properties as an array; this is an override of the
86          * superclass, as it evaluates all the properties.
87          * @return the array of definitions; may be null.
88          * @throws BuildException on error.
89          */

90         public String JavaDoc[] getVariables() throws BuildException {
91
92             List JavaDoc definitions = new LinkedList JavaDoc();
93             ListIterator JavaDoc list = definitions.listIterator();
94             addDefinitionsToList(list);
95             if (definitions.size() == 0) {
96                 return null;
97             } else {
98                 return (String JavaDoc[]) definitions.toArray(new String JavaDoc[definitions.size()]);
99             }
100         }
101
102         /**
103          * Add all definitions (including property sets) to a list.
104          * @param listIt list iterator supporting add method.
105          */

106         public void addDefinitionsToList(ListIterator JavaDoc listIt) {
107             String JavaDoc[] props = super.getVariables();
108             if (props != null) {
109                 for (int i = 0; i < props.length; i++) {
110                     listIt.add("-D" + props[i]);
111                 }
112             }
113             Properties JavaDoc propertySetProperties = mergePropertySets();
114             for (Enumeration JavaDoc e = propertySetProperties.keys();
115                  e.hasMoreElements();) {
116                 String JavaDoc key = (String JavaDoc) e.nextElement();
117                 String JavaDoc value = propertySetProperties.getProperty(key);
118                 listIt.add("-D" + key + "=" + value);
119             }
120         }
121
122         /**
123          * Get the size of the sysproperties instance. This merges all
124          * property sets, so is not an O(1) operation.
125          * @return the size of the sysproperties instance.
126          */

127         public int size() {
128             Properties JavaDoc p = mergePropertySets();
129             return variables.size() + p.size();
130         }
131
132         /**
133          * Cache the system properties and set the system properties to the
134          * new values.
135          * @throws BuildException if Security prevented this operation.
136          */

137         public void setSystem() throws BuildException {
138             try {
139                 sys = System.getProperties();
140                 Properties JavaDoc p = new Properties JavaDoc();
141                 for (Enumeration JavaDoc e = sys.propertyNames(); e.hasMoreElements();) {
142                     String JavaDoc name = (String JavaDoc) e.nextElement();
143                     p.put(name, sys.getProperty(name));
144                 }
145                 p.putAll(mergePropertySets());
146                 for (Enumeration JavaDoc e = variables.elements(); e.hasMoreElements();) {
147                     Environment.Variable v = (Environment.Variable) e.nextElement();
148                     v.validate();
149                     p.put(v.getKey(), v.getValue());
150                 }
151                 System.setProperties(p);
152             } catch (SecurityException JavaDoc e) {
153                 throw new BuildException("Cannot modify system properties", e);
154             }
155         }
156
157         /**
158          * Restore the system properties to the cached value.
159          * @throws BuildException if Security prevented this operation, or
160          * there were no system properties to restore.
161          */

162         public void restoreSystem() throws BuildException {
163             if (sys == null) {
164                 throw new BuildException("Unbalanced nesting of SysProperties");
165             }
166
167             try {
168                 System.setProperties(sys);
169                 sys = null;
170             } catch (SecurityException JavaDoc e) {
171                 throw new BuildException("Cannot modify system properties", e);
172             }
173         }
174
175         /**
176          * Create a deep clone.
177          * @return a cloned instance of SysProperties.
178          * @exception CloneNotSupportedException for signature.
179          */

180         public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
181             try {
182                 SysProperties c = (SysProperties) super.clone();
183                 c.variables = (Vector JavaDoc) variables.clone();
184                 c.propertySets = (Vector JavaDoc) propertySets.clone();
185                 return c;
186             } catch (CloneNotSupportedException JavaDoc e) {
187                 return null;
188             }
189         }
190
191         /**
192          * Add a propertyset to the total set.
193          * @param ps the new property set.
194          */

195         public void addSyspropertyset(PropertySet ps) {
196             propertySets.addElement(ps);
197         }
198
199         /**
200          * Add a propertyset to the total set.
201          * @param ps the new property set.
202          * @since Ant 1.6.3
203          */

204         public void addSysproperties(SysProperties ps) {
205             variables.addAll(ps.variables);
206             propertySets.addAll(ps.propertySets);
207         }
208
209         /**
210          * Merge all property sets into a single Properties object.
211          * @return the merged object.
212          */

213         private Properties JavaDoc mergePropertySets() {
214             Properties JavaDoc p = new Properties JavaDoc();
215             for (Enumeration JavaDoc e = propertySets.elements();
216                  e.hasMoreElements();) {
217                 PropertySet ps = (PropertySet) e.nextElement();
218                 p.putAll(ps.getProperties());
219             }
220             return p;
221         }
222
223     }
224
225     /**
226      * Constructor uses the VM we are running on now.
227      */

228     public CommandlineJava() {
229         setVm(JavaEnvUtils.getJreExecutable("java"));
230         setVmversion(JavaEnvUtils.getJavaVersion());
231     }
232
233     /**
234      * Create a new argument to the java program.
235      * @return an argument to be configured.
236      */

237     public Commandline.Argument createArgument() {
238         return javaCommand.createArgument();
239     }
240
241     /**
242      * Create a new JVM argument.
243      * @return an argument to be configured.
244      */

245     public Commandline.Argument createVmArgument() {
246         return vmCommand.createArgument();
247     }
248
249     /**
250      * Add a system property.
251      * @param sysp a property to be set in the JVM.
252      */

253     public void addSysproperty(Environment.Variable sysp) {
254         sysProperties.addVariable(sysp);
255     }
256
257     /**
258      * Add a set of system properties.
259      * @param sysp a set of properties.
260      */

261     public void addSyspropertyset(PropertySet sysp) {
262         sysProperties.addSyspropertyset(sysp);
263     }
264
265     /**
266      * Add a set of system properties.
267      * @param sysp a set of properties.
268      * @since Ant 1.6.3
269      */

270     public void addSysproperties(SysProperties sysp) {
271         sysProperties.addSysproperties(sysp);
272     }
273
274     /**
275      * Set the executable used to start the new JVM.
276      * @param vm the executable to use.
277      */

278     public void setVm(String JavaDoc vm) {
279         vmCommand.setExecutable(vm);
280     }
281
282     /**
283      * Set the JVM version required.
284      * @param value the version required.
285      */

286     public void setVmversion(String JavaDoc value) {
287         vmVersion = value;
288     }
289
290     /**
291      * Set whether system properties will be copied to the cloned VM--as
292      * well as the bootclasspath unless you have explicitly specified
293      * a bootclasspath.
294      * @param cloneVm if true copy the system properties.
295      * @since Ant 1.7
296      */

297     public void setCloneVm(boolean cloneVm) {
298         this.cloneVm = cloneVm;
299     }
300
301     /**
302      * Get the current assertions.
303      * @return assertions or null.
304      */

305     public Assertions getAssertions() {
306         return assertions;
307     }
308
309     /**
310      * Add an assertion set to the command.
311      * @param assertions assertions to make.
312      */

313     public void setAssertions(Assertions assertions) {
314         this.assertions = assertions;
315     }
316
317     /**
318      * Set a jar file to execute via the -jar option.
319      * @param jarpathname the pathname of the jar to execute.
320      */

321     public void setJar(String JavaDoc jarpathname) {
322         javaCommand.setExecutable(jarpathname);
323         executeJar = true;
324     }
325
326     /**
327      * Get the name of the jar to be run.
328      * @return the pathname of the jar file to run via -jar option
329      * or <tt>null</tt> if there is no jar to run.
330      * @see #getClassname()
331      */

332     public String JavaDoc getJar() {
333         if (executeJar) {
334             return javaCommand.getExecutable();
335         }
336         return null;
337     }
338
339     /**
340      * Set the classname to execute.
341      * @param classname the fully qualified classname.
342      */

343     public void setClassname(String JavaDoc classname) {
344         javaCommand.setExecutable(classname);
345         executeJar = false;
346     }
347
348     /**
349      * Get the name of the class to be run.
350      * @return the name of the class to run or <tt>null</tt> if there is no class.
351      * @see #getJar()
352      */

353     public String JavaDoc getClassname() {
354         if (!executeJar) {
355             return javaCommand.getExecutable();
356         }
357         return null;
358     }
359
360     /**
361      * Create a classpath.
362      * @param p the project to use to create the path.
363      * @return a path to be configured.
364      */

365     public Path createClasspath(Project p) {
366         if (classpath == null) {
367             classpath = new Path(p);
368         }
369         return classpath;
370     }
371
372     /**
373      * Create a boot classpath.
374      * @param p the project to use to create the path.
375      * @return a path to be configured.
376      * @since Ant 1.6
377      */

378     public Path createBootclasspath(Project p) {
379         if (bootclasspath == null) {
380             bootclasspath = new Path(p);
381         }
382         return bootclasspath;
383     }
384
385     /**
386      * Get the vm version.
387      * @return the vm version.
388      */

389     public String JavaDoc getVmversion() {
390         return vmVersion;
391     }
392
393     /**
394      * Get the command line to run a Java vm.
395      * @return the list of all arguments necessary to run the vm.
396      */

397     public String JavaDoc[] getCommandline() {
398         //create the list
399
List JavaDoc commands = new LinkedList JavaDoc();
400         final ListIterator JavaDoc listIterator = commands.listIterator();
401         //fill it
402
addCommandsToList(listIterator);
403         //convert to an array
404
return (String JavaDoc[]) commands.toArray(new String JavaDoc[commands.size()]);
405     }
406
407     /**
408      * Add all the commands to a list identified by the iterator passed in.
409      * @param listIterator an iterator that supports the add method.
410      * @since Ant 1.6
411      */

412     private void addCommandsToList(final ListIterator JavaDoc listIterator) {
413         //create the command to run Java, including user specified options
414
getActualVMCommand().addCommandToList(listIterator);
415         // properties are part of the vm options...
416
sysProperties.addDefinitionsToList(listIterator);
417
418         if (isCloneVm()) {
419             SysProperties clonedSysProperties = new SysProperties();
420             PropertySet ps = new PropertySet();
421             PropertySet.BuiltinPropertySetName sys =
422                 new PropertySet.BuiltinPropertySetName();
423             sys.setValue("system");
424             ps.appendBuiltin(sys);
425             clonedSysProperties.addSyspropertyset(ps);
426             clonedSysProperties.addDefinitionsToList(listIterator);
427         }
428         //boot classpath
429
Path bcp = calculateBootclasspath(true);
430         if (bcp.size() > 0) {
431             listIterator.add("-Xbootclasspath:" + bcp.toString());
432         }
433         //main classpath
434
if (haveClasspath()) {
435             listIterator.add("-classpath");
436             listIterator.add(
437                     classpath.concatSystemClasspath("ignore").toString());
438         }
439         //now any assertions are added
440
if (getAssertions() != null) {
441             getAssertions().applyAssertions(listIterator);
442         }
443         // JDK usage command line says that -jar must be the first option, as there is
444
// a bug in JDK < 1.4 that forces the jvm type to be specified as the first
445
// option, it is appended here as specified in the docs even though there is
446
// in fact no order.
447
if (executeJar) {
448             listIterator.add("-jar");
449         }
450         // this is the classname to run as well as its arguments.
451
// in case of 'executeJar', the executable is a jar file.
452
javaCommand.addCommandToList(listIterator);
453     }
454
455     /**
456      * Specify max memory of the JVM.
457      * -mx or -Xmx depending on VM version.
458      * @param max the string to pass to the jvm to specifiy the max memory.
459      */

460     public void setMaxmemory(String JavaDoc max) {
461         this.maxMemory = max;
462     }
463
464     /**
465      * Get a string description.
466      * @return the command line as a string.
467      */

468     public String JavaDoc toString() {
469         return Commandline.toString(getCommandline());
470     }
471
472     /**
473      * Return a String that describes the command and arguments suitable for
474      * verbose output before a call to <code>Runtime.exec(String[])<code>.
475      * @return the description string.
476      * @since Ant 1.5
477      */

478     public String JavaDoc describeCommand() {
479         return Commandline.describeCommand(getCommandline());
480     }
481
482     /**
483      * Return a String that describes the java command and arguments
484      * for in-VM executions.
485      *
486      * <p>The class name is the executable in this context.</p>
487      * @return the description string.
488      * @since Ant 1.5
489      */

490     public String JavaDoc describeJavaCommand() {
491         return Commandline.describeCommand(getJavaCommand());
492     }
493
494     /**
495      * Get the VM command parameters, including memory settings.
496      * @return the VM command parameters.
497      */

498     protected Commandline getActualVMCommand() {
499         Commandline actualVMCommand = (Commandline) vmCommand.clone();
500         if (maxMemory != null) {
501             if (vmVersion.startsWith("1.1")) {
502                 actualVMCommand.createArgument().setValue("-mx" + maxMemory);
503             } else {
504                 actualVMCommand.createArgument().setValue("-Xmx" + maxMemory);
505             }
506         }
507         return actualVMCommand;
508     }
509
510     /**
511      * Get the size of the java command line. This is a fairly intensive
512      * operation, as it has to evaluate the size of many components.
513      * @return the total number of arguments in the java command line.
514      * @see #getCommandline()
515      * @deprecated since 1.7.
516      * Please dont use this, it effectively creates the
517      * entire command.
518      */

519     public int size() {
520         int size = getActualVMCommand().size() + javaCommand.size()
521             + sysProperties.size();
522         // cloned system properties
523
if (isCloneVm()) {
524             size += System.getProperties().size();
525         }
526         // classpath is "-classpath <classpath>" -> 2 args
527
if (haveClasspath()) {
528             size += 2;
529         }
530         // bootclasspath is "-Xbootclasspath:<classpath>" -> 1 arg
531
if (calculateBootclasspath(true).size() > 0) {
532             size++;
533         }
534         // jar execution requires an additional -jar option
535
if (executeJar) {
536             size++;
537         }
538         //assertions take up space too
539
if (getAssertions() != null) {
540             size += getAssertions().size();
541         }
542         return size;
543     }
544
545     /**
546      * Get the Java command to be used.
547      * @return the java command--not a clone.
548      */

549     public Commandline getJavaCommand() {
550         return javaCommand;
551     }
552
553     /**
554      * Get the VM command, including memory.
555      * @return A deep clone of the instance's VM command, with memory settings added.
556      */

557     public Commandline getVmCommand() {
558         return getActualVMCommand();
559     }
560
561     /**
562      * Get the classpath for the command.
563      * @return the classpath or null.
564      */

565     public Path getClasspath() {
566         return classpath;
567     }
568
569     /**
570      * Get the boot classpath.
571      * @return boot classpath or null.
572      */

573     public Path getBootclasspath() {
574         return bootclasspath;
575     }
576
577     /**
578      * Cache current system properties and set them to those in this
579      * Java command.
580      * @throws BuildException if Security prevented this operation.
581      */

582     public void setSystemProperties() throws BuildException {
583         sysProperties.setSystem();
584     }
585
586     /**
587      * Restore the cached system properties.
588      * @throws BuildException if Security prevented this operation, or
589      * there was no system properties to restore
590      */

591     public void restoreSystemProperties() throws BuildException {
592         sysProperties.restoreSystem();
593     }
594
595     /**
596      * Get the system properties object.
597      * @return The system properties object.
598      */

599     public SysProperties getSystemProperties() {
600         return sysProperties;
601     }
602
603     /**
604      * Deep clone the object.
605      * @return a CommandlineJava object.
606      * @throws BuildException if anything went wrong.
607      * @throws CloneNotSupportedException never.
608      */

609     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
610         try {
611             CommandlineJava c = (CommandlineJava) super.clone();
612             c.vmCommand = (Commandline) vmCommand.clone();
613             c.javaCommand = (Commandline) javaCommand.clone();
614             c.sysProperties = (SysProperties) sysProperties.clone();
615             if (classpath != null) {
616                 c.classpath = (Path) classpath.clone();
617             }
618             if (bootclasspath != null) {
619                 c.bootclasspath = (Path) bootclasspath.clone();
620             }
621             if (assertions != null) {
622                 c.assertions = (Assertions) assertions.clone();
623             }
624             return c;
625         } catch (CloneNotSupportedException JavaDoc e) {
626             throw new BuildException(e);
627         }
628     }
629
630     /**
631      * Clear out the java arguments.
632      */

633     public void clearJavaArgs() {
634         javaCommand.clearArgs();
635     }
636
637     /**
638      * Determine whether the classpath has been specified, and whether it shall
639      * really be used or be nulled by build.sysclasspath.
640      * @return true if the classpath is to be used.
641      * @since Ant 1.6
642      */

643     protected boolean haveClasspath() {
644         Path fullClasspath = classpath != null
645             ? classpath.concatSystemClasspath("ignore") : null;
646         return fullClasspath != null
647             && fullClasspath.toString().trim().length() > 0;
648     }
649
650     /**
651      * Determine whether the bootclasspath has been specified, and whether it
652      * shall really be used (build.sysclasspath could be set or the VM may not
653      * support it).
654      *
655      * @param log whether to log a warning if a bootclasspath has been
656      * specified but will be ignored.
657      * @return true if the bootclasspath is to be used.
658      * @since Ant 1.6
659      */

660     protected boolean haveBootclasspath(boolean log) {
661         return calculateBootclasspath(log).size() > 0;
662     }
663
664     /**
665      * Calculate the bootclasspath based on the bootclasspath
666      * specified, the build.sysclasspath and ant.build.clonevm magic
667      * properties as well as the cloneVm attribute.
668      * @param log whether to write messages to the log.
669      * @since Ant 1.7
670      */

671     private Path calculateBootclasspath(boolean log) {
672         if (vmVersion.startsWith("1.1")) {
673             if (bootclasspath != null && log) {
674                 bootclasspath.log("Ignoring bootclasspath as "
675                                   + "the target VM doesn't support it.");
676             }
677         } else {
678             if (bootclasspath != null) {
679                 return bootclasspath.concatSystemBootClasspath(isCloneVm()
680                                                                ? "last"
681                                                                : "ignore");
682             } else if (isCloneVm()) {
683                 return Path.systemBootClasspath;
684             }
685         }
686         return new Path(null);
687     }
688
689     /**
690      * Find out whether either of the cloneVm attribute or the magic property
691      * ant.build.clonevm has been set.
692      * @return <code>boolean</code>.
693      * @since 1.7
694      */

695     private boolean isCloneVm() {
696         return cloneVm
697             || "true".equals(System.getProperty("ant.build.clonevm"));
698     }
699 }
700
Popular Tags