1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package au.csiro.netcdf;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.PrintWriter;
25 import java.io.StringWriter;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.apache.commons.cli.BasicParser;
30 import org.apache.commons.cli.CommandLine;
31 import org.apache.commons.cli.HelpFormatter;
32 import org.apache.commons.cli.Option;
33 import org.apache.commons.cli.OptionBuilder;
34 import org.apache.commons.cli.Options;
35 import org.apache.commons.cli.ParseException;
36 import org.apache.log4j.Logger;
37
38 import ucar.nc2.Dimension;
39 import ucar.nc2.NetcdfFileWriteable;
40 import au.csiro.netcdf.cli.Command;
41 import au.csiro.netcdf.cli.CommandLineOptionsComparator;
42 import au.csiro.netcdf.util.Util;
43
44
45
46
47
48
49
50
51
52
53
54 public class NcDefineDimension implements Command
55 {
56
57
58
59 public static final String NC_DEFINE_DIM_COMMAND_NAME = "ncdefineDim";
60
61
62
63
64 public static final String OUTPUT_FILE = "outputFileName";
65
66
67
68
69 public static final String DIMENSION_SIZE = "dimensionSize";
70
71
72
73
74 public static final String DIMENSION_NAME = "dimensionName";
75
76
77
78
79
80 public static final String IS_LARGE_FILE = "largeFileSupport";
81
82
83
84
85 private static final Logger LOG = Logger.getLogger(NcDefineDimension.class.getName());
86
87
88
89
90 private Options options = null;
91
92
93
94
95 public NcDefineDimension()
96 {
97 this.options = createOptions();
98 }
99
100
101
102
103
104
105 @Override
106 public void execute(String[] args) throws ParseException, IOException, IllegalArgumentException
107 {
108
109 CommandLine parsedCommandLine = new BasicParser().parse(this.options, args);
110
111
112 String outputFilenameArg = (parsedCommandLine.hasOption(OUTPUT_FILE)) ? parsedCommandLine
113 .getOptionValue(OUTPUT_FILE) : "";
114 String dimensionSizeArg = (parsedCommandLine.hasOption(DIMENSION_SIZE)) ? parsedCommandLine
115 .getOptionValue(DIMENSION_SIZE) : "";
116 String dimensionNameArg = (parsedCommandLine.hasOption(DIMENSION_NAME)) ? parsedCommandLine
117 .getOptionValue(DIMENSION_NAME) : "";
118 boolean isUnlimited = dimensionSizeArg.isEmpty();
119 boolean isLargeFileSupport = parsedCommandLine.hasOption(IS_LARGE_FILE);
120
121
122 if (Util.fileExists(outputFilenameArg)
123 && Util.getExistingFile(outputFilenameArg).length() >= MAX_32BIT_OFFSET_FILE_SIZE
124 && !isLargeFileSupport)
125 {
126 throw new IllegalArgumentException("The netCDF file will be too large, please use " + IS_LARGE_FILE
127 + " flag.");
128 }
129
130
131 int dimensionSize = 0;
132 if (!isUnlimited)
133 {
134 dimensionSize = NcDefineDimension.mapStringToDimensionSize(dimensionSizeArg);
135 }
136
137 this.execute(outputFilenameArg, dimensionNameArg, dimensionSize, isUnlimited, isLargeFileSupport);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 public void execute(String outputFilename, String dimensionName, int dimensionSize, boolean isUnlimited,
163 boolean isLargeFileSupport) throws IOException, SecurityException, IllegalStateException
164 {
165
166 NetcdfFileWriteable ncfile = null;
167
168
169 File outputFile = new File(outputFilename);
170 if (outputFile.exists())
171 {
172 ncfile = NetcdfFileWriteable.openExisting(outputFilename, false
173
174
175
176
177
178
179
180
181
182
183 );
184 try
185 {
186
187 ncfile.setRedefineMode(true);
188
189 Dimension dimension = new Dimension(dimensionName, dimensionSize
190
191 , true /* isShared */,
192 isUnlimited
193
194
195 this.checkDimensionLimitiations(ncfile, dimension);
196
197
198 ncfile.addDimension(null, dimension);
199
200
201 ncfile.setRedefineMode(false);
202 }
203 finally
204 {
205 if(ncfile!=null)
206 {
207 try
208 {
209 ncfile.close();
210 }
211 catch(Exception e)
212 {
213 LOG.error("Could not close file: " + outputFilename, e);
214 }
215 }
216 }
217 }
218 else
219 {
220 File parentFile = outputFile.getParentFile();
221 if (parentFile != null)
222 {
223 parentFile.mkdirs();
224 }
225 ncfile = NetcdfFileWriteable.createNew(outputFilename, false
226
227
228
229
230
231
232
233
234
235 );
236 try
237 {
238 Dimension dimension = new Dimension(dimensionName, Integer.valueOf(dimensionSize).intValue()
239
240
241
242 ,
243 true
244
245
246 this.checkDimensionLimitiations(ncfile, dimension);
247
248
249 ncfile.addDimension(null, dimension);
250
251
252 ncfile.create();
253 }
254 finally
255 {
256 if(ncfile!=null)
257 {
258 try
259 {
260 ncfile.close();
261 }
262 catch(Exception e)
263 {
264 LOG.error("Could not close file: " + outputFilename, e);
265 }
266 }
267 }
268 }
269 }
270
271
272
273
274
275
276 @Override
277 public String getCommandName()
278 {
279 return NcDefineDimension.NC_DEFINE_DIM_COMMAND_NAME;
280 }
281
282
283
284
285
286
287 public String toString()
288 {
289
290 String header = "Define a dimension in a netCDF file.";
291 String footer = "\nExample: ncdefinedim -outputFileName ABC.nc -dimensionName Lat -dimensionSize 560\n"
292 + "Will add a dimension called Lat allowing a maximum of 560 values to the file ABC.nc. "
293 + "The file will be created if it doesn't already exist. ";
294 StringWriter sw = new StringWriter();
295 HelpFormatter formatter = new HelpFormatter();
296 formatter.setOptionComparator(new CommandLineOptionsComparator());
297 formatter.printHelp(new PrintWriter(sw), PRINT_WIDTH, NcDefineDimension.NC_DEFINE_DIM_COMMAND_NAME, header,
298 this.options, 0, 1, footer);
299 return sw.toString();
300 }
301
302
303
304
305
306
307 @SuppressWarnings("static-access")
308 @Override
309 public Options createOptions()
310 {
311 Option outputFileName = OptionBuilder.withArgName("file").hasArg().withDescription(
312 "1: the filename of the netCDF file to be created.").isRequired(true).withLongOpt(OUTPUT_FILE).create(
313 "o");
314
315
316 Option dimensionSize = OptionBuilder.withArgName("integer").hasArg().withDescription(
317 "2: the size of the dimension, OPTIONAL, if not specified dimension is considered to be \"unlimited\".")
318 .isRequired(false).withLongOpt(DIMENSION_SIZE).create("s");
319
320 Option dimensionName = OptionBuilder.withArgName("text").hasArg().withDescription(
321 "3: the name to be given to the dimension.").isRequired(true).withLongOpt(DIMENSION_NAME).create("d");
322
323 Option largeFileSupport = OptionBuilder.withDescription(
324 "4: OPTIONAL, set if more than 2 GB of data will need to be stored in this file.").isRequired(false)
325 .withLongOpt(IS_LARGE_FILE).create("l");
326
327 Options options = new Options();
328
329 options.addOption(outputFileName);
330 options.addOption(dimensionSize);
331 options.addOption(dimensionName);
332 options.addOption(largeFileSupport);
333
334 return options;
335 }
336
337
338
339
340 public String getUsageString()
341 {
342 return this.toString();
343 }
344
345
346
347
348
349
350
351
352 public String validCommand(String[] commandLine)
353 {
354 String errorMsg = "";
355
356
357 try
358 {
359
360 CommandLine parsedCommandLine = new BasicParser().parse(this.options, commandLine);
361
362
363 String outputFilenameArg = (parsedCommandLine.hasOption(OUTPUT_FILE)) ? parsedCommandLine
364 .getOptionValue(OUTPUT_FILE) : "";
365 String dimensionSizeArg = (parsedCommandLine.hasOption(DIMENSION_SIZE)) ? parsedCommandLine
366 .getOptionValue(DIMENSION_SIZE) : "";
367 boolean isLargeFileSupport = parsedCommandLine.hasOption(IS_LARGE_FILE);
368
369
370 if (Util.fileExists(outputFilenameArg)
371 && Util.getExistingFile(outputFilenameArg).length() >= MAX_32BIT_OFFSET_FILE_SIZE
372 && !isLargeFileSupport)
373 {
374 throw new IllegalArgumentException("The netCDF file will be too large, please use " + IS_LARGE_FILE
375 + " flag.");
376 }
377
378
379 if (!dimensionSizeArg.isEmpty())
380 {
381 NcDefineDimension.mapStringToDimensionSize(dimensionSizeArg);
382 }
383 }
384 catch (ParseException pe)
385 {
386 errorMsg = errorMsg + "\n" + pe.getMessage();
387 }
388 catch (IllegalArgumentException iae)
389 {
390 errorMsg = errorMsg + "\n" + iae.getMessage();
391 }
392
393 return errorMsg;
394 }
395
396
397
398
399
400
401
402
403
404
405 private static int mapStringToDimensionSize(String dimensionSizeArg)
406 {
407 if (Util.validateNumber(dimensionSizeArg))
408 {
409 return Integer.valueOf(dimensionSizeArg).intValue();
410 }
411 else
412 {
413 throw new IllegalArgumentException(NcDefineDimension.DIMENSION_SIZE + " value is not an integer: "
414 + dimensionSizeArg);
415 }
416 }
417
418
419
420
421
422
423
424
425
426
427
428 private void checkDimensionLimitiations(NetcdfFileWriteable ncfile, Dimension dimension)
429 throws IllegalStateException
430 {
431 List<Dimension> dimensions = new ArrayList<Dimension>();
432 try
433 {
434 dimensions = ncfile.getDimensions();
435 }
436 catch (NullPointerException npe)
437 {
438
439
440 LOG.info("NetCDF file has no dimensions defined.");
441 }
442
443
444
445 if (!dimensions.isEmpty() && ncfile.getUnlimitedDimension() != null && dimension.isUnlimited())
446 {
447 throw new IllegalStateException("Can not add an unlimited dimension to a netCDF-3 file "
448 + "that already contains an unlimited dimension: " + ncfile.getUnlimitedDimension());
449 }
450 }
451 }