Clad User Manual - How to Implement a Command Line Application

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

Internal

Overview

Declare the Maven Dependency

<dependency>
    <groupId>io.novaordis.clad</groupId>
    <artifactId>novaordis-clad</artifactId>
    <version>...</version>
</dependency>

Provide an ApplicationRuntime Implementation

Extend ApplicationRuntimeBase, into a "clad" sub-package of your project. This is the recommended approach. If you need more flexibility, you can implement ApplicationRuntime interface.

The application runtime functionality is related to the following aspects:

Specify a Default Command

To provide a default command, implement public String getDefaultCommandName(). For more details on the default command, see "Default Command" section.

Define Global Options

All clad-based application automatically support a number of "universal" global options, such as -v|--verbose. For more details on global options, see "Global Options" section.

Logging

Logging in clad-based application is conceptually explained here: "clad Concepts - Logging".

SLF4J Integration

clad relies on SLF4J API, but does not enforce any binding. It is up to your application to define a binding among its dependencies. For more details see SLF4J - No StaticLoggerBinder.

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
</dependency>

TODO: Come up with a deterministic way to specify the slf4j-log4j12 version, in relation to the slf4j-api version used by clad.

Log4j

Come up with a solution for:

log4j:WARN No appenders could be found for logger (io.novaordis.clad.configuration.ConfigurationImpl).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

In-line Application Help

If a text file named <application-name>.txt is placed in the same package as the ApplicationRuntime implementation class, its content is rendered to stdout every time the in-line application help is invoked with no-argument "help" command:

   <app-name> help|--help|-h

The length of a text line should not be larger than 99.

Macros

The help renderer recognizes several macros, which are replaced by dynamically generated content at runtime.

@COMMANDS@ - inserts the list of commands available to the application. The runtime builds that list via introspection looking for classes that implement the Command interface.


Wrapper

java -cp ... io.novaordis.clad.CommandLineApplication

Application Name

The application name should be provided as a system property argument to java, in the wrapper:

-Dapplication.name=Release

Package the application runtime implementation class and the commands in a JAR (or place them in a directory).

Set “application.name” as a system property. If the application runtime implementation class is BlueApplicationRuntime, the application.name must be “blue”.

Make sure the JAR or the directory is first on the class path (otherwise other <your-command-name>Command.class, if exist, will be instantiated first).

Implement Commands

Implement the Command interface or extend CommandBase (recommended).

The implementation class must be named <command-name>Command.

Example: PrintCommand will be matched to the "print" command. BusinessScenarioCommand will be matched to the "business-scenario" command.

Clarify capitalization.

Relationship between Command and ApplicationRuntime

If a specific command does not need an application runtime instance (thus the framework is not required to instantiate an application runtime for it), the Command.needsRuntime() implementation must return false. By default CommandBase.needsRuntime() returns true.

In-Line Command Help

If a text file named <command-name>.txt is placed in the same package as the command implementation class, the framework will send the content of the file to stdout when in-line command help is requested:

    <wrapper> help|--help|-h <command>

For a command whose name is blue, the in-line command help file should be named blue.txt.

For a command whose name is business-scenario, the in-line command help file should be named business-scenario.txt.

The length of a text line should not be larger than 99.

Command Options

To declare that a command requires a specific option, override Command.requiredOptions().

To declare that a command accepts a specific option, override Command.optionalOptions().

In both cases, the set should contain option definitions only, the command instance is not expected to maintain any state inside the option instances, they can be recreated on each invocation. Example:

@Override
public Set<Option> optionalOptions() {
    return new HashSet<>(Collections.singletonList(new BooleanOption("ignore-faults")));
}

Implementation Examples:

https://github.com/NovaOrdis/esa/blob/master/src/main/java/io/novaordis/esa/extensions/bscenarios/BusinessScenarioCommand.java

Default Command

If no command is specified, the framework will use the “default command”, if there is one. If not, the application should display:

 [error]: no command specified on command line and no default command was configured.

Instructions on how to configure the default command.

Command Execution

execute() will be called on the main thread.