001    /*
002     * Cobertura - http://cobertura.sourceforge.net/
003     *
004     * Copyright (C) 2005 Grzegorz Lukasik
005     *
006     * Note: This file is dual licensed under the GPL and the Apache
007     * Source License (so that it can be used from both the main
008     * Cobertura classes and the ant tasks).
009     *
010     * Cobertura is free software; you can redistribute it and/or modify
011     * it under the terms of the GNU General Public License as published
012     * by the Free Software Foundation; either version 2 of the License,
013     * or (at your option) any later version.
014     *
015     * Cobertura is distributed in the hope that it will be useful, but
016     * WITHOUT ANY WARRANTY; without even the implied warranty of
017     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018     * General Public License for more details.
019     *
020     * You should have received a copy of the GNU General Public License
021     * along with Cobertura; if not, write to the Free Software
022     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
023     * USA
024     */
025    
026    package net.sourceforge.cobertura.util;
027    
028    import java.io.BufferedReader;
029    import java.io.File;
030    import java.io.FileReader;
031    import java.io.FileWriter;
032    import java.io.IOException;
033    import java.util.ArrayList;
034    import java.util.List;
035    
036    import org.apache.log4j.Logger;
037    
038    /**
039     * Helper class for storing long command lines inside temporary file.
040     * <p>
041     * Typical usage:
042     * 
043     * <pre>
044     *  builder = new CommandLineBuilder();
045     *  builder.addArg("--someoption");
046     *  builder.addArg("optionValue");
047     *  ...
048     *  builder.saveArgs();
049     *  doSomething(builder.getCommandLineFile());
050     *  builder.dispose();
051     * </pre>
052     * 
053     * It will save options in <code>builder.getCommandLineFile()</code>. Options
054     * will be stored one in a line. To retrieve options from file helper method can
055     * be used (see documentation):
056     * 
057     * <pre>
058     * String[] args = CommandLineBuilder.preprocessCommandLineArguments(args);
059     * </pre>
060     * 
061     * </p>
062     * 
063     * <p>
064     * NOTICE: No protection against line separators in arguments, should be OK for
065     * Cobertura needs.
066     * </p>
067     * <p>
068     * NOTICE: This class depends on local machine settings (line separator, default
069     * encoding). If arguments are saved on different machine than they are loaded,
070     * results are unspecified. No problem in Cobertura.
071     * </p>
072     * 
073     * @author Grzegorz Lukasik
074     */
075    public class CommandLineBuilder {
076            private static final Logger logger = Logger
077                            .getLogger(CommandLineBuilder.class);
078    
079            private static final String LINESEP = System.getProperty("line.separator");
080    
081            // File that will be used to store arguments
082            private File commandLineFile = null;
083    
084            // Writer that will be used to write arguments to the file
085            private FileWriter commandLineWriter = null;
086    
087            /**
088             * Creates a new instance of the builder. Instances of this class should not
089             * be reused to create many command lines.
090             * 
091             * @throws IOException
092             *             if problems with creating temporary file for storing command
093             *             line occur
094             */
095            public CommandLineBuilder() throws IOException {
096                    commandLineFile = File.createTempFile("cobertura.", ".cmdline");
097                    commandLineFile.deleteOnExit();
098                    commandLineWriter = new FileWriter(commandLineFile);
099            }
100    
101            /**
102             * Adds command line argument. Each argument can be thought as a single cell
103             * in array passed to main method. This method should not be used after
104             * arguments were saved.
105             * 
106             * @param arg command line argument to save
107             * @throws IOException
108             *             if problems with temporary file occur
109             * @throws NullPointerException 
110             *             if <code>arg</code> is <code>null</code>            
111             */
112            public void addArg(String arg) throws IOException {
113                    if( arg==null)
114                            throw new NullPointerException();
115                    commandLineWriter.write(arg + LINESEP);
116            }
117    
118            
119            /**
120             * Adds two command line arguments. Convienience function, calls
121             * {@link #addArg(String)} two times.   
122             * 
123             * @param arg1 first command line argument to save
124             * @param arg2 second command line argument to save
125             * @throws IOException
126             *             if problems with temporary file occur
127             * @throws NullPointerException 
128             *             if any <code>arg</code> is <code>null</code>            
129             */
130        public void addArg(String arg1, String arg2) throws IOException {
131            addArg(arg1);
132            addArg(arg2);
133        }
134    
135        
136            /**
137             * Saves options and made file available to use. Use method
138             * {@link #getCommandLineFile} to get the file the arguments are saved in.
139             * 
140             * @throws IOException
141             *             if problems with temporary file occur
142             */
143            public void saveArgs() throws IOException {
144                    commandLineWriter.flush();
145                    commandLineWriter.close();
146            }
147    
148            /**
149             * Gets absolute path to the file with saved arguments. Notice, that however
150             * this method can be used as soon as an instance of this class is created,
151             * arguments should be read from the file after a call to
152             * {@link #saveArgs} method.
153             * 
154             * @return absolute path to the file with arguments
155             */
156            public String getCommandLineFile() {
157                    return commandLineFile.getAbsolutePath();
158            }
159    
160            /**
161             * Explicity frees all resources associated with this instance. Result of
162             * any other method call after disposing an instance of this class is
163             * unspecified.
164             */
165            public void dispose() {
166                    commandLineFile.delete();
167            }
168    
169            /**
170             * Loads arguments from file if <code>--commandsfile</code> option is used. Checks
171             * if passed array contains <code>--commandsfile</code> String, and if
172             * so arguments from file specified in the very next array cell are read. If
173             * there are more then one <code>--commandsfile</code> the result is unspecified. 
174             *
175             * @return The list of arguments read from commandsfile, or
176             *         <code>args</code> if commandsfile option was not specified
177             *         or the file cannot be read.
178             * @throws NullPointerException if args is null, or any argument is null
179             * @throws IllegalArgumentException if --commandsfile is specified as last option
180             * @throws IOException if I/O related error with temporary command line file occur
181             */
182            public static String[] preprocessCommandLineArguments(String[] args) throws IOException {
183                    boolean hasCommandsFile = false;
184                    String commandsFileName = null;
185                    for (int i = 0; i < args.length; i++) {
186                            if ( args[i].equals( "--commandsfile")) {
187                                    if( i==args.length-1) {
188                                            throw new IllegalArgumentException("'--commandsfile' specified as last option.");
189                                    }
190                                    hasCommandsFile = true;
191                                    commandsFileName = args[++i];
192                            }
193                    }
194    
195                    if (hasCommandsFile) {
196                            List arglist = new ArrayList();
197                            BufferedReader bufferedReader = null;
198    
199                            try {
200                                    bufferedReader = new BufferedReader(new FileReader(
201                                                    commandsFileName));
202                                    String line;
203    
204                                    while ((line = bufferedReader.readLine()) != null)
205                                            arglist.add(line);
206    
207                            } catch (IOException e) {
208                                    logger.info( "I/O error when reading temporary commands file", e);
209                                    throw new IOException( "Unable to read temporary commands file "
210                                                    + commandsFileName + ".");
211                            } finally {
212                                    if (bufferedReader != null) {
213                                            try {
214                                                    bufferedReader.close();
215                                            } catch (IOException e) {
216                                            }
217                                    }
218                            }
219    
220                            args = (String[]) arglist.toArray(new String[arglist.size()]);
221                    }
222                    return args;
223            }
224    }