Coverage Report - au.csiro.netcdf.NcCSVExtract
 
Classes in this File Line Coverage Branch Coverage Complexity
NcCSVExtract
98%
81/82
90%
29/32
4.429
 
 1  
 /**
 2  
  * Copyright 2010, CSIRO Australia.
 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  
 package au.csiro.netcdf;
 18  
 
 19  
 import java.io.BufferedReader;
 20  
 import java.io.FileReader;
 21  
 import java.io.IOException;
 22  
 import java.io.PrintWriter;
 23  
 import java.io.StringWriter;
 24  
 
 25  
 import org.apache.commons.cli.BasicParser;
 26  
 import org.apache.commons.cli.CommandLine;
 27  
 import org.apache.commons.cli.HelpFormatter;
 28  
 import org.apache.commons.cli.Option;
 29  
 import org.apache.commons.cli.OptionBuilder;
 30  
 import org.apache.commons.cli.Options;
 31  
 import org.apache.commons.cli.ParseException;
 32  
 
 33  
 import au.csiro.netcdf.cli.Command;
 34  
 import au.csiro.netcdf.cli.CommandLineOptionsComparator;
 35  
 import au.csiro.netcdf.util.CSVTokenizer;
 36  
 import au.csiro.netcdf.util.Util;
 37  
 
 38  
 /**
 39  
  * The <strong>ncextractcsv</strong> command reads a specified column of data from a comma separated 
 40  
  * file and then writes this column to standard output.
 41  
  * <br/>
 42  
  * 
 43  
  * Copyright 2010, CSIRO Australia 
 44  
  * All rights reserved.
 45  
  * 
 46  
  * @author $Author: robertbridle $ on 18/03/2010
 47  
  * @version $Revision: 84 $ $Date: 2010-08-25 15:56:46 +1000 (Wed, 25 Aug 2010) $ $Id: CSVExtract.java 6525
 48  
  *          2010-03-17 23:39:33Z che256 $
 49  
  */
 50  
 public class NcCSVExtract implements Command
 51  
 {
 52  
     /**
 53  
      * The command name
 54  
      */
 55  
     public static final String EXTRACT_COMMAND_NAME = "ncextractcsv";
 56  
     
 57  
     /**
 58  
      * The name of the command line option used for specifying the input csv file name.
 59  
      */
 60  
     public static final String INPUT_FILE = "inputFileName";
 61  
     
 62  
     /**
 63  
      * The name of the command line option used for specifying the index of the column.
 64  
      */
 65  
     public static final String COLUMN_INDEX = "columnIndex";
 66  
     
 67  
     /**
 68  
      * The name of the command line option used for specifying the start row.
 69  
      */
 70  
     public static final String START_ROW = "startRow";
 71  
     
 72  
     /**
 73  
      * The name of the command line option used for specifying the end row.
 74  
      */
 75  
     public static final String END_ROW = "endRow";
 76  
     
 77  
     /**
 78  
      * Command options
 79  
      */
 80  26
     private Options options = null;
 81  
     
 82  
     /**
 83  
      * Constructor
 84  
      */
 85  26
     public NcCSVExtract()
 86  
     {
 87  26
         this.options = createOptions();        
 88  26
     }
 89  
 
 90  
     /**
 91  
      * Create the command line options for this CSVExtract command.
 92  
      * 
 93  
      * @return the command line options for this command.
 94  
      */
 95  
     @Override
 96  
     @SuppressWarnings("static-access")
 97  
     public Options createOptions()
 98  
     {
 99  84
         Option fileName = OptionBuilder.withArgName("file").hasArg().withDescription(
 100  56
                 "1: the filename of csv file to read.").isRequired(true).withLongOpt(INPUT_FILE).create("i");
 101  
 
 102  84
         Option columnIndex = OptionBuilder.withArgName("integer").hasArg().withDescription(
 103  56
                 "2: the column index from the csv file to read.").isRequired(true).withLongOpt(COLUMN_INDEX)
 104  28
                 .create("c");
 105  
 
 106  84
         Option startRow = OptionBuilder.withArgName("integer").hasArg().withDescription(
 107  84
                 "3: the row to read from. OPTIONAL, if not specified row 0 is used.").isRequired(false).withLongOpt(
 108  56
                 START_ROW).create("s");
 109  
 
 110  84
         Option endRow = OptionBuilder.withArgName("integer").hasArg().withDescription(
 111  56
                 "4: the row to read to. OPTIONAL, if not specified the last row in the csv file is used.").isRequired(
 112  56
                 false).withLongOpt(END_ROW).create("e");
 113  
 
 114  28
         Options options = new Options();
 115  
 
 116  28
         options.addOption(fileName);
 117  28
         options.addOption(columnIndex);
 118  28
         options.addOption(startRow);
 119  28
         options.addOption(endRow);
 120  
 
 121  28
         return options;
 122  
     }
 123  
 
 124  
     /**
 125  
      * Run the CSVExtract command.
 126  
      * 
 127  
      * @param args
 128  
      *            command line arguments.
 129  
      * @throws ParseException
 130  
      *             thrown if the command line arguments can not be parsed.
 131  
      * @throws IOException
 132  
      *             thrown if netCDF can to be written to or read from.
 133  
      */
 134  
     @Override
 135  
     public void execute(String[] args) throws ParseException, IOException
 136  
     {
 137  
         // parse the command line arguments
 138  10
         CommandLine parsedCommandLine = new BasicParser().parse(options, args);
 139  
 
 140  10
         String filename = parsedCommandLine.getOptionValue(INPUT_FILE);
 141  10
         int numRecords = Util.fastFileLineCounter(filename);
 142  10
         int columnIndex = getIntValueByName(parsedCommandLine, COLUMN_INDEX);
 143  
 
 144  10
         int rowCount = 0;
 145  10
         int startRow = parsedCommandLine.hasOption(START_ROW) ? getIntValueByName(parsedCommandLine, START_ROW) : 0;
 146  10
         int endRow = parsedCommandLine.hasOption(END_ROW) ? getIntValueByName(parsedCommandLine, END_ROW) : numRecords;
 147  10
         endRow = (endRow > numRecords) ? numRecords : endRow;
 148  
 
 149  10
         BufferedReader input = new BufferedReader(new FileReader(filename));
 150  
         try
 151  
         {
 152  10
             String line = null;
 153  38
             while ((line = input.readLine()) != null)
 154  
             {
 155  
                 // only read the required lines
 156  20
                 if (rowCount >= startRow && rowCount <= endRow)
 157  
                 {
 158  16
                     String[] values = new CSVTokenizer(line).getAllColumns();
 159  
 
 160  16
                     String value = "";
 161  
                     try
 162  
                     {
 163  16
                         value = values[columnIndex];
 164  
                     }
 165  2
                     catch (ArrayIndexOutOfBoundsException ex)
 166  
                     {
 167  2
                         throw new ParseException("incorrect column index");
 168  
                     }
 169  14
                     System.out.println(value);
 170  14
                     rowCount++;
 171  
                 }
 172  
                 else
 173  
                 {
 174  4
                     rowCount++;
 175  
                     continue;
 176  
                 }
 177  
             }
 178  
         }
 179  
         finally
 180  2
         {
 181  10
             input.close();
 182  2
         }
 183  8
     }
 184  
 
 185  
     /**
 186  
      * @return the command name for this command.
 187  
      */
 188  
     @Override
 189  
     public String getCommandName()
 190  
     {
 191  38
         return EXTRACT_COMMAND_NAME;
 192  
     }
 193  
 
 194  
     /**
 195  
      * Determine if this command is valid, check its syntax. Required options: inputFileName, columnIndex Type check:
 196  
      * columnIndex, startRow, endRow can only be integer
 197  
      * 
 198  
      * @param commandLine command line arguments.
 199  
      * @return error if found.
 200  
      */
 201  
     @Override
 202  
     public String validCommand(String[] commandLine)
 203  
     {
 204  22
         StringBuffer errorMsg = new StringBuffer();
 205  22
         CommandLine parsedCommandLine = null;
 206  
 
 207  
         // check required options are provided
 208  
         try
 209  
         {
 210  22
             parsedCommandLine = new BasicParser().parse(options, commandLine);
 211  
         }
 212  2
         catch (ParseException ex)
 213  
         {
 214  2
             return ex.getMessage();
 215  
         }
 216  
 
 217  
         // check command name
 218  20
         String commandName = parsedCommandLine.getArgs()[0];
 219  20
         if (!getCommandName().equals(commandName))
 220  
         {
 221  0
             return commandName + " is not a valid command.";
 222  
         }
 223  
 
 224  
         // check if specified file exist
 225  20
         String fileName = parsedCommandLine.getOptionValue(INPUT_FILE);
 226  20
         if (!Util.fileExists(fileName))
 227  
         {
 228  2
             return fileName + " does not exist.";
 229  
         }
 230  
         
 231  
         // validate file type
 232  18
         if (!".csv".equalsIgnoreCase(Util.getFileExtension(fileName)))
 233  
         {
 234  2
             return fileName + " is not a csv file.";
 235  
         }
 236  
 
 237  
         // check required types:
 238  
         // i.e. columnIndex, startRow and endRow are of integer type
 239  16
         int index = getIntValueByName(parsedCommandLine, COLUMN_INDEX);
 240  16
         if (index == -1)
 241  
         {
 242  2
             errorMsg.append("ColumnIndex has to be a number.");
 243  
         }
 244  
 
 245  16
         if (parsedCommandLine.hasOption(START_ROW))
 246  
         {
 247  8
             index = getIntValueByName(parsedCommandLine, START_ROW);
 248  8
             if (index == -1)
 249  
             {
 250  2
                 errorMsg.append(" startRow has to be a number.");
 251  
             }
 252  
         }
 253  16
         if (parsedCommandLine.hasOption(END_ROW))
 254  
         {
 255  6
             index = getIntValueByName(parsedCommandLine, END_ROW);
 256  6
             if (index == -1)
 257  
             {
 258  2
                 errorMsg.append(" endRow has to be a number.");
 259  
             }
 260  
         }
 261  
 
 262  16
         return errorMsg.toString();
 263  
     }
 264  
 
 265  
     /**
 266  
      * @return the usage for this command.
 267  
      */
 268  
     @Override
 269  
     public String getUsageString()
 270  
     {
 271  
         // generate the help/usage statement
 272  6
         String header = "Extract a block of data from a CSV file. The data can then "
 273  
                 + "be piped into the ncwritevar command to add the data to a variable in a netCDF file.";
 274  6
         String footer = "\nExample: extract -inputFileName modeldata.csv -columnIndex 1 -startRow 2\n"
 275  
                 + "Will write the data contained in the second column of the modeldata.csv file to stdout, "
 276  
                 + "but ignoring the first 2 lines. ";
 277  6
         StringWriter sw = new StringWriter();
 278  6
         HelpFormatter formatter = new HelpFormatter();
 279  6
         formatter.setOptionComparator(new CommandLineOptionsComparator());
 280  6
         formatter.printHelp(new PrintWriter(sw), PRINT_WIDTH, EXTRACT_COMMAND_NAME, header, options, 0, 1, footer);
 281  6
         return sw.toString();
 282  
     }
 283  
 
 284  
     /**
 285  
      * Return integer value of an option using specified name
 286  
      * "-1" is returned if option name or value is not valid
 287  
      * 
 288  
      * @param parsedCommandLine Commandline object
 289  
      * @param opName option name
 290  
      * @return int value
 291  
      */
 292  
     private int getIntValueByName(CommandLine parsedCommandLine, String opName)
 293  
     {
 294  48
         String str = (parsedCommandLine.hasOption(opName)) ? parsedCommandLine.getOptionValue(opName) : "";
 295  
 
 296  48
         if (Util.validateNumber(str))
 297  
         {
 298  42
             return Integer.valueOf(str);
 299  
         }
 300  6
         return -1;
 301  
     }
 302  
 }