______   _   _
|  ____| | | |_|
| |      | |  _   _________   _____   _    _ 
| |      | | | | |  _   _  | |___  | | \  / |
| |      | | | | | | | | | |  ___| |  \ \/ /
| |      | | | | | | | | | | |  _  |   \  /
| |      | | | | | | | | | | | | | |   /  \
| |____  | | | | | | | | | | | |_| |  / /\ \
|______| |_| |_| |_| |_| |_| |_____| |_/  \_|

A Java Command Line Argument Parser Framework

Welcome to Climax

Table of Contents
1. Introduction
1.1. Example of Reflective Interface Definition
1.2. Example of Procedural Definition
1.3. Example of Command Line Option Types
1.4. Example of Default Arguments
1.5. Example of Default and Custom Validation and Parsing
1.6. Example of Automatically-Provided Version Option for Provided Version Information
1.7. Example of Customizable Help Information

1. Introduction

Climax is a Java command line argument parser framework which allows you to create and customize your own command line interface.

Climax has the following features:

  • Two definition modes for parsing command line arguments:
    • Reflective interface definition: useful for implementing less code as possible (Similar to the JewelCli library) (See example).
    • Procedural definition: useful for avoiding use of reflection for performance reasons (See example).
  • Command line options can be defined as any of the following types:
  • Options can be terminative to parsing any other command line argument (Similar to the options --help and --version).
  • Option arguments for an option can be provided separately or provided together as a list using a defined argument separator.
  • Options and non-option arguments can be undocumented.
  • Options and non-option arguments can be provided with default arguments (See example).
  • Option arguments and non-option arguments can be validated and parsed using default and custom logic that can provide user-friendly error messages (See example).
  • The command line program's version option is automatically provided when providing the version information (See example).
  • The command line program's help information and any of its elements can be completely customized (See example).

1.1 Example of Reflective Interface Definition

public final class Base64 {

	interface base64 extends CLIResults {

		OptionGroupResults<Void> getDecode();
		
		ArgGroupResults<FileReader> getFile();
		
		OptionGroupResults<Void> getIgnoreGarbage();
		
		OptionGroupResults<Integer> getWrap();
	}
		
	public static void main(final String[] args) {

		CLIResultsInterface<base64> c = CLIResultsInterface.getInstance(base64.class);
		
		base64 b = c.newCLIResults(args, System.out, System.err);
		
		switch(b.getCLIProcessResult()) {
		
		case ERROR:
			System.exit(1);
			
		case HELP_REQUESTED:
			return;
			
		default:
			break;
		}
		
		// ...
	}
}
$ java -classpath ... Base64 --help
Usage: base64 [OPTION...] FILE

OPTIONS:
  --decode
  --ignore-garbage
  --wrap=-2147483648...2147483647
  --help
      Display this help and exit

$
Back to Introduction

1.2 Example of Procedural Definition

public final class Base64 {
	
	public static void main(final String[] args) {
		
		AbstractFactory factory = AbstractFactory.getDefault();
		
		// create option group for the option --decode
		
		OptionComplete decodeOptionComplete = 
				factory.newOptionCompleteBuilder(
						OptionType.GNU_LONG, "decode")
						.build();
		
		OptionGroupCompleteBuilder<Void> decodeOptionGroupCompleteBuilder =
				factory.newOptionGroupCompleteBuilder(
						Arrays.asList(decodeOptionComplete));
		
		OptionGroupComplete<Void> decodeOptionGroupComplete =
				decodeOptionGroupCompleteBuilder.build();
		
		// create option group for the option --ignore-garbage
		
		OptionComplete ignoreOptionComplete = 
				factory.newOptionCompleteBuilder(
						OptionType.GNU_LONG, "ignore-garbage")
						.build();
		
		OptionGroupCompleteBuilder<Void> ignoreOptionGroupCompleteBuilder =
				factory.newOptionGroupCompleteBuilder(
						Arrays.asList(ignoreOptionComplete));
		
		OptionGroupComplete<Void> ignoreOptionGroupComplete =
				ignoreOptionGroupCompleteBuilder.build();
		
		// create option group for the option --wrap
		
		OptionComplete wrapOptionComplete = 
				factory.newOptionCompleteBuilder(
						OptionType.GNU_LONG, "wrap")
						.usage("--wrap=-2147483648...2147483647")
						.build();
		
		OptionGroupCompleteBuilder<Integer> wrapOptionGroupCompleteBuilder =
				factory.newOptionGroupCompleteBuilder(
						Arrays.asList(wrapOptionComplete));
		
		OptionGroupComplete<Integer> wrapOptionGroupComplete =
				wrapOptionGroupCompleteBuilder
				.argParser(IntegerArgParser.getInstance())
				.argsValidator(SingleArgValidator.getInstance())
				.build();
		
		// create argument group for the FILE argument
		
		ArgGroupCompleteBuilder<FileReader> fileArgGroupCompleteBuilder =
				factory.newArgGroupCompleteBuilder(
					"FILE",
					FileReaderArgParser.getInstance());
		
		ArgGroupComplete<FileReader> fileArgGroupComplete =
				fileArgGroupCompleteBuilder.build();
		
		// gather all option groups
		
		OptionsComplete optionsComplete = factory.newOptionsComplete();
		optionsComplete.addOptionGroupComplete(decodeOptionGroupComplete);
		optionsComplete.addOptionGroupComplete(ignoreOptionGroupComplete);
		optionsComplete.addOptionGroupComplete(wrapOptionGroupComplete);
		
		// gather all argument groups
		
		ArgsComplete argsComplete = factory.newArgsComplete();
		argsComplete.addArgGroupComplete(fileArgGroupComplete);
		
		// create the command line interface
		
		CLI cli = factory.newCLIBuilder("base64")
				.argsComplete(argsComplete)
				.optionsComplete(optionsComplete)
				.build();
		
		switch(cli.process(args, System.out, System.err)) {
		
		case ERROR:
			System.exit(1);
			
		case HELP_REQUESTED:
			return;
			
		default:
			break;
		}
		
		/*
		 * gather the results from the OptionGroupComplete 
		 * and ArgGroupComplete objects
		 */
		 
		// ...		 
	}
}
$ java -classpath ... Base64 --help
Usage: base64 [OPTION...] FILE

OPTIONS:
  --decode
  --ignore-garbage
  --wrap=-2147483648...2147483647
  --help
      Display this help and exit

$
Back to Introduction

1.3 Example of Command Line Option Types

interface base64 extends CLIResults {

	@OptionGroupCompleteSpec(
		options = { 
			@OptionCompleteSpec(optionType = OptionType.POSIX),
			@OptionCompleteSpec(optionType = OptionType.GNU_LONG) 
		}
	)
	OptionGroupResults<Void> getDecode();
	
	ArgGroupResults<FileReader> getFile();
	
	@OptionGroupCompleteSpec(
		options = { 
			@OptionCompleteSpec(optionType = OptionType.POSIX),
			@OptionCompleteSpec(
				optionType = OptionType.GNU_SHORT_LONG, 
				name = "ignore"
			),
			@OptionCompleteSpec(optionType = OptionType.GNU_LONG) 
		}
	)
	OptionGroupResults<Void> getIgnoreGarbage();
	
	@OptionGroupCompleteSpec(
		options = { 
			@OptionCompleteSpec(optionType = OptionType.POSIX),
			@OptionCompleteSpec(optionType = OptionType.GNU_LONG) 
		}
	)
	OptionGroupResults<Integer> getWrap();
}
$ java -classpath ... Base64 --help
Usage: base64 [OPTION...] FILE

OPTIONS:
  -d, --decode
  -i, -ignore, --ignore-garbage
  -w -2147483648...2147483647, --wrap=-2147483648...2147483647
  --help
      Display this help and exit

$
Back to Introduction

1.4 Example of Default Arguments

interface base64 extends CLIResults {

	OptionGroupResults<Void> getDecode();
	
	@ArgGroupCompleteSpec(
		defaultArguments = { "-" } // default is set to standard input
	)	
	ArgGroupResults<FileReader> getFile();
	
	OptionGroupResults<Void> getIgnoreGarbage();
	
	@OptionGroupCompleteSpec(
		defaultArguments = { "76" } // default is set to 76
	)
	OptionGroupResults<Integer> getWrap();
}
Back to Introduction

1.5 Example of Default and Custom Validation and Parsing

interface base64 extends CLIResults {

	OptionGroupResults<Void> getDecode();

	ArgGroupResults<FileReader> getFile();
	
	OptionGroupResults<Void> getIgnoreGarbage();
	
	@OptionGroupCompleteSpec(
		argParserClass = ColumnLimitArgParser.class
	)
	OptionGroupResults<Integer> getWrap();
}

static class ColumnLimitArgParser 
	implements ParameterlessArgParser<Integer> {
	
	private final ArgParser<Integer> argParser;
	
	public ColumnLimitArgParser() {
		
		this.argParser = new IntegerArgParser(
				Integer.valueOf(0),
				Integer.valueOf(Integer.MAX_VALUE));
	}
	
	@Override
	public Integer parse(final String arg) throws ArgParserException {
		return this.argParser.parse(arg);
	}
}
$ java -classpath ... Base64 file1.txt
base64: invalid FILE argument `file1.txt' : cannot find `file1.txt'
Try `base64 --help' for more information
$ touch file1.txt file2.txt
$ java -classpath ... Base64 file1.txt file2.txt
base64: unknown argument(s) : `file2.txt'
Try `base64 --help' for more information
$ java -classpath ... Base64 --wrap=-20000 file1.txt
base64: invalid argument `-20000' for `--wrap' : argument must be no less than 0
Try `base64 --help' for more information
$
Back to Introduction

1.6 Example of Automatically-Provided Version Option for Provided Version Information

@CLISpec(
	programVersion = "${programName}\n" 
		+ "Command line interface provided by" 
		+ " ${org.climax.specTitle} ${org.climax.specVersion}"
)							
interface base64 extends CLIResults {

	OptionGroupResults<Void> getDecode();

	ArgGroupResults<FileReader> getFile();
	
	OptionGroupResults<Void> getIgnoreGarbage();
	
	OptionGroupResults<Integer> getWrap();
}							
$ java -classpath ... Base64 --version
base64
Command line interface provided by Climax 2.0

$							
Back to Introduction

1.7 Example of Customizable Help Information

							
/*
 * adjust the format of the help information to look like the help information of 
 * GNU's base64
 */

@CLISpec(
	helpOptionGroupDocDescription = "display this help and exit",
	helpOptionGroupDocHelp = 
		"      ${format:%-9s;p=usage}  ${description}",
	helpOptionGroupDocOrdinal = 3,
	optionsDocUsage = "[OPTION]...",
	programDescription = 
		"Base64 encode or decode ${argGroupDoc0.argumentType}"
		+ ", or standard input, to standard output.",	
	programHelpBody =
		"Usage: ${programUsage}\n"
		+ "${programDescription}\n\n"
		+ "${optionsDoc.help}\n\n"
		+ "${format:With no %1$s, or when %1$s is -," 
		+ " read standard input." 
		+ ";p=argGroupDoc0.argumentType}",
	programVersion = "${programName}\n" 
		+ "Command line interface provided by" 
		+ " ${org.climax.specTitle} ${org.climax.specVersion}",
	versionOptionGroupDocDescription = 
		"output version information and exit",
	versionOptionGroupDocHelp = 
		"      ${format:%-9s;p=usage}  ${description}",
	versionOptionGroupDocOrdinal = 4
)
interface base64 extends CLIResults {

	@OptionGroupCompleteSpec(
		description = "decode data",
		help = "  ${format:%-20s;p=usage}  ${description}",
		options = { 
			@OptionCompleteSpec(optionType = OptionType.POSIX),
			@OptionCompleteSpec(optionType = OptionType.GNU_LONG) 
		},
		ordinal = 0,
		usage = "${optionDoc0.option}, ${optionDoc1.usage}"
	)
	OptionGroupResults<Void> getDecode();

	@ArgGroupCompleteSpec(
		argsValidatorClass = NoneOrSingleArgValidator.class,
		defaultArguments = { "-" },
		syntax = "[${argumentType}]"
	)
	ArgGroupResults<FileReader> getFile();

	@OptionGroupCompleteSpec(
		description = "when decoding, ignore non-alphabet characters",
		help = "  ${format:%-20s;p=usage}  ${description}",
		options = { 
			@OptionCompleteSpec(optionType = OptionType.POSIX),
			@OptionCompleteSpec(optionType = OptionType.GNU_LONG) 
		},
		ordinal = 1,
		usage = "${optionDoc0.option}, ${optionDoc1.usage}"
	)	
	OptionGroupResults<Void> getIgnoreGarbage();
	
	@OptionGroupCompleteSpec(
		argParserClass = ColumnLimitArgParser.class,
		defaultArguments = { "76" },
		description = 
			"wrap encoded lines after COLS character (default 76).",
		help = "  ${format:%-20s;p=usage}  ${description}\n"
			+ "${format:%-22s;v= }     Use 0 to disable line wrapping\n",
		options = { 
			@OptionCompleteSpec( 
				optionType = OptionType.POSIX,
				usage = "${option} COLS" 
			),
			@OptionCompleteSpec( 
				optionType = OptionType.GNU_LONG,
				usage = "${option}${optionTypeDoc.assignmentOperator}COLS" 
			) 
		},
		ordinal = 2,
		usage = "${optionDoc0.option}, ${optionDoc1.usage}"
	)
	OptionGroupResults<Integer> getWrap();
				
}

static class ColumnLimitArgParser 
	implements ParameterlessArgParser<Integer> {
	
	private final ArgParser<Integer> argParser;
	
	public ColumnLimitArgParser() {
		
		this.argParser = new IntegerArgParser(
				Integer.valueOf(0),
				Integer.valueOf(Integer.MAX_VALUE));
	}
	
	@Override
	public Integer parse(final String arg) throws ArgParserException {
		return this.argParser.parse(arg);
	}
}
$ java -classpath ... Base64 --help
Usage: base64 [OPTION]... [FILE]
Base64 encode or decode FILE, or standard input, to standard output.

  -d, --decode          decode data
  -i, --ignore-garbage  when decoding, ignore non-alphabet characters
  -w, --wrap=COLS       wrap encoded lines after COLS character (default 76).
                           Use 0 to disable line wrapping

      --help     display this help and exit
      --version  output version information and exit

With no FILE, or when FILE is -, read standard input.

$
Back to Introduction
 

Valid HTML 4.01 Strict Valid CSS!