KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > util > Commandline


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001-2003, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37 /*
38  * The Apache Software License, Version 1.1
39  *
40  * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
41  * reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  *
47  * 1. Redistributions of source code must retain the above copyright
48  * notice, this list of conditions and the following disclaimer.
49  *
50  * 2. Redistributions in binary form must reproduce the above copyright
51  * notice, this list of conditions and the following disclaimer in
52  * the documentation and/or other materials provided with the
53  * distribution.
54  *
55  * 3. The end-user documentation included with the redistribution, if
56  * any, must include the following acknowlegement:
57  * "This product includes software developed by the
58  * Apache Software Foundation (http://www.apache.org/)."
59  * Alternately, this acknowlegement may appear in the software itself,
60  * if and wherever such third-party acknowlegements normally appear.
61  *
62  * 4. The names "The Jakarta Project", "Ant", and "Apache Software
63  * Foundation" must not be used to endorse or promote products derived
64  * from this software without prior written permission. For written
65  * permission, please contact apache@apache.org.
66  *
67  * 5. Products derived from this software may not be called "Apache"
68  * nor may "Apache" appear in their names without prior written
69  * permission of the Apache Group.
70  *
71  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
72  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
73  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
74  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
75  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
76  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
77  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
78  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
79  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
80  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
81  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82  * SUCH DAMAGE.
83  * ====================================================================
84  *
85  * This software consists of voluntary contributions made by many
86  * individuals on behalf of the Apache Software Foundation. For more
87  * information on the Apache Software Foundation, please see
88  * <http://www.apache.org/>.
89  */

90 package net.sourceforge.cruisecontrol.util;
91
92 import net.sourceforge.cruisecontrol.CruiseControlException;
93 import org.apache.log4j.Logger;
94
95 import java.io.File JavaDoc;
96 import java.io.IOException JavaDoc;
97 import java.util.StringTokenizer JavaDoc;
98 import java.util.Vector JavaDoc;
99
100 /**
101  * Commandline objects help handling command lines specifying processes to
102  * execute.
103  *
104  * The class can be used to define a command line as nested elements or as a
105  * helper to define a command line by an application.
106  * <p>
107  * <code>
108  * &lt;someelement&gt;<br>
109  * &nbsp;&nbsp;&lt;acommandline executable="/executable/to/run"&gt;<br>
110  * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 1" /&gt;<br>
111  * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument line="argument_1 argument_2 argument_3" /&gt;<br>
112  * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 4" /&gt;<br>
113  * &nbsp;&nbsp;&lt;/acommandline&gt;<br>
114  * &lt;/someelement&gt;<br>
115  * </code>
116  * The element <code>someelement</code> must provide a method
117  * <code>createAcommandline</code> which returns an instance of this class.
118  *
119  * @author thomas.haas@softwired-inc.com
120  * @author <a HREF="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
121  */

122 public class Commandline implements Cloneable JavaDoc {
123
124     private static final Logger LOG = Logger.getLogger(Commandline.class);
125
126     private Vector JavaDoc arguments = new Vector JavaDoc();
127     private String JavaDoc executable = null;
128     private File JavaDoc workingDir = null;
129
130     public Commandline(String JavaDoc toProcess) {
131         super();
132         String JavaDoc[] tmp = new String JavaDoc[0];
133         try {
134             tmp = translateCommandline(toProcess);
135         } catch (CruiseControlException e) {
136             LOG.error("Error translating Commandline.", e);
137         }
138         if (tmp != null && tmp.length > 0) {
139             setExecutable(tmp[0]);
140             for (int i = 1; i < tmp.length; i++) {
141                 createArgument().setValue(tmp[i]);
142             }
143         }
144     }
145
146     public Commandline() {
147         super();
148     }
149     
150     protected File JavaDoc getWorkingDir() {
151       return workingDir;
152     }
153
154     /**
155      * Used for nested xml command line definitions.
156      */

157     public static class Argument {
158
159         private String JavaDoc[] parts;
160
161         /**
162          * Sets a single commandline argument.
163          *
164          * @param value a single commandline argument.
165          */

166         public void setValue(String JavaDoc value) {
167             parts = new String JavaDoc[] { value };
168         }
169
170         /**
171          * Line to split into several commandline arguments.
172          *
173          * @param line line to split into several commandline arguments
174          */

175         public void setLine(String JavaDoc line) {
176             if (line == null) {
177                 return;
178             }
179             try {
180                 parts = translateCommandline(line);
181             } catch (CruiseControlException e) {
182                 LOG.error("Error translating Commandline.", e);
183             }
184         }
185
186         /**
187          * Sets a single commandline argument to the absolute filename
188          * of the given file.
189          *
190          * @param value a single commandline argument.
191          */

192         public void setFile(File JavaDoc value) {
193             parts = new String JavaDoc[] { value.getAbsolutePath()};
194         }
195
196         /**
197          * Returns the parts this Argument consists of.
198          */

199         public String JavaDoc[] getParts() {
200             return parts;
201         }
202     }
203
204     /**
205      * Class to keep track of the position of an Argument.
206      */

207     // <p>This class is there to support the srcfile and targetfile
208
// elements of &lt;execon&gt; and &lt;transform&gt; - don't know
209
// whether there might be additional use cases.</p> --SB
210
public class Marker {
211
212         private int position;
213         private int realPos = -1;
214
215         Marker(int position) {
216             this.position = position;
217         }
218
219         /**
220          * Return the number of arguments that preceeded this marker.
221          *
222          * <p>The name of the executable - if set - is counted as the
223          * very first argument.</p>
224          */

225         public int getPosition() {
226             if (realPos == -1) {
227                 realPos = (executable == null ? 0 : 1);
228                 for (int i = 0; i < position; i++) {
229                     Argument arg = (Argument) arguments.elementAt(i);
230                     realPos += arg.getParts().length;
231                 }
232             }
233             return realPos;
234         }
235     }
236
237     /**
238      * Creates an argument object.
239      *
240      * <p>Each commandline object has at most one instance of the
241      * argument class. This method calls
242      * <code>this.createArgument(false)</code>.</p>
243      *
244      * @see #createArgument(boolean)
245      * @return the argument object.
246      */

247     public Argument createArgument() {
248         return this.createArgument(false);
249     }
250
251     /**
252      * Creates an argument object and adds it to our list of args.
253      *
254      * <p>Each commandline object has at most one instance of the
255      * argument class.</p>
256      *
257      * @param insertAtStart if true, the argument is inserted at the
258      * beginning of the list of args, otherwise it is appended.
259      */

260     public Argument createArgument(boolean insertAtStart) {
261         Argument argument = new Argument();
262         if (insertAtStart) {
263             arguments.insertElementAt(argument, 0);
264         } else {
265             arguments.addElement(argument);
266         }
267         return argument;
268     }
269
270     /**
271      * Sets the executable to run.
272      */

273     public void setExecutable(String JavaDoc executable) {
274         if (executable == null || executable.length() == 0) {
275             return;
276         }
277         this.executable =
278             executable.replace('/', File.separatorChar).replace('\\', File.separatorChar);
279     }
280
281     public String JavaDoc getExecutable() {
282         return executable;
283     }
284
285     public void addArguments(String JavaDoc[] line) {
286         for (int i = 0; i < line.length; i++) {
287             createArgument().setValue(line[i]);
288         }
289     }
290
291     /**
292      * Returns the executable and all defined arguments.
293      */

294     public String JavaDoc[] getCommandline() {
295         final String JavaDoc[] args = getArguments();
296         if (executable == null) {
297             return args;
298         }
299         final String JavaDoc[] result = new String JavaDoc[args.length + 1];
300         result[0] = executable;
301         System.arraycopy(args, 0, result, 1, args.length);
302         return result;
303     }
304
305     /**
306      * Returns all arguments defined by <code>addLine</code>,
307      * <code>addValue</code> or the argument object.
308      */

309     public String JavaDoc[] getArguments() {
310         Vector JavaDoc result = new Vector JavaDoc(arguments.size() * 2);
311         for (int i = 0; i < arguments.size(); i++) {
312             Argument arg = (Argument) arguments.elementAt(i);
313             String JavaDoc[] s = arg.getParts();
314             if (s != null) {
315                 for (int j = 0; j < s.length; j++) {
316                     result.addElement(s[j]);
317                 }
318             }
319         }
320
321         String JavaDoc[] res = new String JavaDoc[result.size()];
322         result.copyInto(res);
323         return res;
324     }
325
326     public String JavaDoc toString() {
327         return toString(getCommandline());
328     }
329
330     /**
331      * Put quotes around the given String if necessary.
332      *
333      * <p>If the argument doesn't include spaces or quotes, return it
334      * as is. If it contains double quotes, use single quotes - else
335      * surround the argument by double quotes.</p>
336      *
337      * @exception CruiseControlException if the argument contains both, single
338      * and double quotes.
339      */

340     public static String JavaDoc quoteArgument(String JavaDoc argument) throws CruiseControlException {
341         if (argument.indexOf("\"") > -1) {
342             if (argument.indexOf("\'") > -1) {
343                 throw new CruiseControlException("Can't handle single and double quotes in same argument");
344             } else {
345                 return '\'' + argument + '\'';
346             }
347         } else if (argument.indexOf("\'") > -1 || argument.indexOf(" ") > -1) {
348             return '\"' + argument + '\"';
349         } else {
350             return argument;
351         }
352     }
353
354     public static String JavaDoc toString(String JavaDoc[] line) {
355         // empty path return empty string
356
if (line == null || line.length == 0) {
357             return "";
358         }
359
360         // path containing one or more elements
361
final StringBuffer JavaDoc result = new StringBuffer JavaDoc();
362         for (int i = 0; i < line.length; i++) {
363             if (i > 0) {
364                 result.append(' ');
365             }
366             try {
367                 result.append(quoteArgument(line[i]));
368             } catch (CruiseControlException e) {
369                 LOG.error("Error quoting argument.", e);
370             }
371         }
372         return result.toString();
373     }
374
375     public static String JavaDoc[] translateCommandline(String JavaDoc toProcess) throws CruiseControlException {
376         if (toProcess == null || toProcess.length() == 0) {
377             return new String JavaDoc[0];
378         }
379
380         // parse with a simple finite state machine
381

382         final int normal = 0;
383         final int inQuote = 1;
384         final int inDoubleQuote = 2;
385         int state = normal;
386         StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(toProcess, "\"\' ", true);
387         Vector JavaDoc v = new Vector JavaDoc();
388         StringBuffer JavaDoc current = new StringBuffer JavaDoc();
389
390         while (tok.hasMoreTokens()) {
391             String JavaDoc nextTok = tok.nextToken();
392             switch (state) {
393                 case inQuote :
394                     if ("\'".equals(nextTok)) {
395                         state = normal;
396                     } else {
397                         current.append(nextTok);
398                     }
399                     break;
400                 case inDoubleQuote :
401                     if ("\"".equals(nextTok)) {
402                         state = normal;
403                     } else {
404                         current.append(nextTok);
405                     }
406                     break;
407                 default :
408                     if ("\'".equals(nextTok)) {
409                         state = inQuote;
410                     } else if ("\"".equals(nextTok)) {
411                         state = inDoubleQuote;
412                     } else if (" ".equals(nextTok)) {
413                         if (current.length() != 0) {
414                             v.addElement(current.toString());
415                             current.setLength(0);
416                         }
417                     } else {
418                         current.append(nextTok);
419                     }
420                     break;
421             }
422         }
423
424         if (current.length() != 0) {
425             v.addElement(current.toString());
426         }
427
428         if (state == inQuote || state == inDoubleQuote) {
429             throw new CruiseControlException("unbalanced quotes in " + toProcess);
430         }
431
432         String JavaDoc[] args = new String JavaDoc[v.size()];
433         v.copyInto(args);
434         return args;
435     }
436
437     public int size() {
438         return getCommandline().length;
439     }
440
441     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
442         super.clone();
443         
444         Commandline c = new Commandline();
445         c.setExecutable(executable);
446         c.addArguments(getArguments());
447         return c;
448     }
449
450     /**
451      * Clear out the whole command line. */

452     public void clear() {
453         executable = null;
454         arguments.removeAllElements();
455     }
456
457     /**
458      * Clear out the arguments but leave the executable in place for another operation.
459      */

460     public void clearArgs() {
461         arguments.removeAllElements();
462     }
463
464     /**
465      * Return a marker.
466      *
467      * <p>This marker can be used to locate a position on the
468      * commandline - to insert something for example - when all
469      * parameters have been set.</p>
470      */

471     public Marker createMarker() {
472         return new Marker(arguments.size());
473     }
474
475     /**
476      * Sets execution directory.
477      */

478     public void setWorkingDirectory(String JavaDoc path) throws CruiseControlException {
479         if (path != null) {
480             File JavaDoc dir = new File JavaDoc(path);
481             checkWorkingDir(dir);
482             workingDir = dir;
483         } else {
484             workingDir = null;
485         }
486     }
487    
488     /**
489      * Sets exeuction directory
490      */

491     public void setWorkingDir(File JavaDoc workingDir) throws CruiseControlException {
492         checkWorkingDir(workingDir);
493         this.workingDir = workingDir;
494     }
495
496     // throws an exception if the specified working directory is non null
497
// and not a valid working directory
498
private void checkWorkingDir(File JavaDoc dir) throws CruiseControlException {
499         if (dir != null) {
500             if (!dir.exists()) {
501                 throw new CruiseControlException(
502                     "Working directory \"" + dir.getAbsolutePath() + "\" does not exist!");
503             } else if (!dir.isDirectory()) {
504                 throw new CruiseControlException(
505                     "Path \"" + dir.getAbsolutePath() + "\" does not specify a directory.");
506             }
507         }
508     }
509
510     public File JavaDoc getWorkingDirectory() {
511         return workingDir;
512     }
513
514     /**
515      * Executes the command.
516      */

517     public Process JavaDoc execute() throws IOException JavaDoc {
518         Process JavaDoc process;
519
520         if (workingDir == null) {
521             LOG.debug("Executing \"" + this + "\"");
522             process = Runtime.getRuntime().exec(getCommandline());
523         } else {
524             LOG.debug(
525                 "Executing \""
526                     + this
527                     + "\" in directory "
528                     + workingDir.getAbsolutePath());
529             process = Runtime.getRuntime().exec(getCommandline(), null, workingDir);
530         }
531
532         return process;
533     }
534
535 }
536
Popular Tags