Clad User Manual - Concepts: Difference between revisions
No edit summary |
|||
(36 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
* [[Clad_User_Manual#Subjects|clad User Manual]] | * [[Clad_User_Manual#Subjects|clad User Manual]] | ||
=Application Configuration= | |||
During the initialization phase, a clad-based application runtime gathers configuration information from different sources (command line [[#Options|options]], the optional configuration file, etc) and exposes them internally via a <tt>Configuration</tt> implementation. | |||
The configuration elements can be typed, as in the case of <tt>Configuration.isVerbose()</tt> or <tt>Configuration.getGlobalOptions()</tt>, or de-typed, where a configuration element referred by label is returned as String (or null, if that configuration element does not exist). From this perspective, the Configuration instance acts as a <tt>Map<String, String></tt>. A recommended usage pattern would be the following: | |||
<pre> | |||
// | |||
// during initialization ... | |||
// | |||
Configuration c = ... | |||
c.set(MyApplicationConfigurationLabels.LABEL1, "something"); | |||
// | |||
// at runtime | |||
// | |||
String value = c.get(MyApplicationConfigurationLabels.LABEL1); | |||
</pre> | |||
==Hardcoded Configuration Defaults== | |||
The conventional place where an application provides hardcoded defaults for application-specific configuration elements that are not specified in the configuration file or on the command line is in the <tt>ApplicationRuntimeBase.init()</tt> override. | |||
=Command= | =Command= | ||
A command accepts command options and arguments. | A command accepts [[#Options|command options]] and [[#Command_Arguments|arguments]]. | ||
==Default Command== | ==Default Command== | ||
An application may not have a default command. In this case, the <tt>ApplicationRuntime</tt> implementation of <tt> | An application may not have a default command. In this case, the <tt>ApplicationRuntime</tt> implementation of <tt>getDefaultCommand()</tt> must return null. | ||
==Universal Commands== | ==Universal Commands== | ||
The framework comes with built-in support for a set of universal commands that are available for any application. Those include: | |||
===version=== | |||
All clad-based applications support the "version" command, which pulls version and release date bundled with the distribution and displays it in a standard format: | |||
<pre> | |||
version 1.0 | |||
release date 01/26/16 | |||
</pre> | |||
Standard handling for version and release data metadata is based on [[Nova Ordis Utilities Version Metadata Handling|novaordis-utilities Version Metadata Handling]] mechanism. | |||
=Command Arguments= | =Command Arguments= | ||
The command arguments are a list of space separated free-format strings, that are not options, and that have a special significance for the command. | |||
The command is given a chance to recognize arguments that make sense to it, and "consume" them. The command implementation has a chance to do that when implementing the <tt>configure(...)</tt> method of the Command interface, or when overriding the corresponding method of the CommandBase abstract class. | |||
The CommandBase <tt>configure(...)</tt> implementation parses the declared options for the command, so the command only accepts options, it is sufficient to use the default implementation. However, for a more nuanced handling of the command line argument, use: | |||
<pre> | |||
@Override | |||
public void configure(int from, List<String> commandLineArguments) throws Exception { | |||
super.configure(from, commandLineArguments); | |||
// | |||
// perform additional handling here and remove the arguments that make sense to us | |||
// from the given list | |||
// | |||
} | |||
</pre> | |||
=Options= | =Options= | ||
Line 43: | Line 103: | ||
=Logging= | =Logging= | ||
The clad framework comes pre-bundled with SLF4J API support, so the command line applications build with clad can use SLF4J for logging. However, clad does not favor any binding, so the application should provide its own SLF4J binding library and the backend logging framework. For details on how do do that, see [[Clad_User_Manual_-_How_to_Implement_a_Command_Line_Application#SLF4J_Integration|How to Implement a Command Line Application - SLF4J Integration]]. | |||
==Debug Logging== | |||
Use SLF4J API <tt>debug()</tt> method: | |||
<pre> | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
... | |||
private static final Logger log = LoggerFactory.getLogger(MyClass.class); | |||
... | |||
log.debug("..."); | |||
</pre> | |||
These log messages will be automatically sent to stdout when the [[#-v.7C--verbose|-v|--verbose]] option is used. | |||
==Console Output== | |||
Use ApplicationRuntime's <tt>info(...)</tt>, <tt>warn(...)</tt> and <tt>error(...)</tt> API calls. | |||
===Info Display=== | |||
===Warning Display=== | |||
===Error Display=== | |||
An alternative mechanism to signal critical user errors is to throw UserErrorExceptions. See "[[#Error_Handling|Error Handling]]" section. | |||
=Error Handling= | =Error Handling= | ||
If | If the underlying command fails because of what the user did, or by invalid input data entered by the user, and the behavior can be corrected by modifying the user input, the conventional approach should be to throw an UserErrorException with a human-readable message. The default implementation will detect this situation, display the error message embedded within the exception following the error display rules (also see "[[#Error_Display|Error Display]]" section), and terminate the JVM by executing System.exit() with a non-zero exit code. | ||
<blockquote style="background-color: Tomato; border: solid thin red;"> | |||
:'''TODO''': Modify UserErrorException to allow for injection of a custom exit code. Modify clad upper layer to pick up that exit code and pass it as an argument to System.exit();<br> | |||
</blockquote> | |||
=Configuration File= | =Configuration File= | ||
Each command line option has a configuration file correspondent. Command line value takes precedence over the configuration file value. | Each command line option has a configuration file correspondent. Command line value takes precedence over the configuration file value. | ||
=Variable Support= | |||
clad-based applications support "runtime variables" that are defined by the runtime and resolved when <tt>ApplicationRuntime.resolveVariables(String s)</tt> is invoked. The method replaces the runtime variables found in the given string with values provided by the runtime. If no corresponding value is found, or in other words, the variable cannot be resolved, no replacement is made, the variable is left in the <tt>${var_name}</tt> format. | |||
The variables are resolved by the runtime with <tt>getValue(String variableName)</tt> method. If the runtime has a value for the specific variable, it will return a non-null string value. If the variable cannot be resolved, the method will return null. The method must be overridden by subclasses, the default implementation does not resolve any variable. | |||
{{Error|'''TODO''': The io.novaordis.clad.variable package is under development at the time of the writing. When it is done, update this paragraph.}} | |||
{{Error|Since clad was written, variable support has evolved in novaordis-utilities, if in the position to edit this paragraph, sync with [[Nova Ordis Generic Variable and Expression System|novaordis-utilities Generic Variable System]]}} |
Latest revision as of 19:01, 18 September 2017
Internal
Application Configuration
During the initialization phase, a clad-based application runtime gathers configuration information from different sources (command line options, the optional configuration file, etc) and exposes them internally via a Configuration implementation.
The configuration elements can be typed, as in the case of Configuration.isVerbose() or Configuration.getGlobalOptions(), or de-typed, where a configuration element referred by label is returned as String (or null, if that configuration element does not exist). From this perspective, the Configuration instance acts as a Map<String, String>. A recommended usage pattern would be the following:
// // during initialization ... // Configuration c = ... c.set(MyApplicationConfigurationLabels.LABEL1, "something"); // // at runtime // String value = c.get(MyApplicationConfigurationLabels.LABEL1);
Hardcoded Configuration Defaults
The conventional place where an application provides hardcoded defaults for application-specific configuration elements that are not specified in the configuration file or on the command line is in the ApplicationRuntimeBase.init() override.
Command
A command accepts command options and arguments.
Default Command
An application may not have a default command. In this case, the ApplicationRuntime implementation of getDefaultCommand() must return null.
Universal Commands
The framework comes with built-in support for a set of universal commands that are available for any application. Those include:
version
All clad-based applications support the "version" command, which pulls version and release date bundled with the distribution and displays it in a standard format:
version 1.0 release date 01/26/16
Standard handling for version and release data metadata is based on novaordis-utilities Version Metadata Handling mechanism.
Command Arguments
The command arguments are a list of space separated free-format strings, that are not options, and that have a special significance for the command.
The command is given a chance to recognize arguments that make sense to it, and "consume" them. The command implementation has a chance to do that when implementing the configure(...) method of the Command interface, or when overriding the corresponding method of the CommandBase abstract class.
The CommandBase configure(...) implementation parses the declared options for the command, so the command only accepts options, it is sufficient to use the default implementation. However, for a more nuanced handling of the command line argument, use:
@Override public void configure(int from, List<String> commandLineArguments) throws Exception { super.configure(from, commandLineArguments); // // perform additional handling here and remove the arguments that make sense to us // from the given list // }
Options
The options (global or specific to a certain command) use the GNU command line option syntax:
-o <value> | --option=<value>
Global Options
The global options apply to the application runtime, and they are not specific to a certain command.
Universal Global Options
All clad-based application automatically support the following global options. There is no need to declared them among the "required" or "optional" global options for a specific application.
-v|--verbose
-v or --verbose turn on DEBUG on the underlying CONSOLE appender, so the application will display internal execution information at stdout. In order to be displayed in this mode, the internal execution information must be logged by the application with SLFJ4 debug() method. For more details on how to program debug logging, see How to Implement a Command Line Application - Debug Logging.
-d|--debug
-d or --debug, in addition to logging debug information at the CONSOLE the way -v|--verbose options do, start the underlying JVM in debug mode, so a debugger can be attached to it.
Command Options
Logging
The clad framework comes pre-bundled with SLF4J API support, so the command line applications build with clad can use SLF4J for logging. However, clad does not favor any binding, so the application should provide its own SLF4J binding library and the backend logging framework. For details on how do do that, see How to Implement a Command Line Application - SLF4J Integration.
Debug Logging
Use SLF4J API debug() method:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; ... private static final Logger log = LoggerFactory.getLogger(MyClass.class); ... log.debug("...");
These log messages will be automatically sent to stdout when the -v|--verbose option is used.
Console Output
Use ApplicationRuntime's info(...), warn(...) and error(...) API calls.
Info Display
Warning Display
Error Display
An alternative mechanism to signal critical user errors is to throw UserErrorExceptions. See "Error Handling" section.
Error Handling
If the underlying command fails because of what the user did, or by invalid input data entered by the user, and the behavior can be corrected by modifying the user input, the conventional approach should be to throw an UserErrorException with a human-readable message. The default implementation will detect this situation, display the error message embedded within the exception following the error display rules (also see "Error Display" section), and terminate the JVM by executing System.exit() with a non-zero exit code.
- TODO: Modify UserErrorException to allow for injection of a custom exit code. Modify clad upper layer to pick up that exit code and pass it as an argument to System.exit();
Configuration File
Each command line option has a configuration file correspondent. Command line value takes precedence over the configuration file value.
Variable Support
clad-based applications support "runtime variables" that are defined by the runtime and resolved when ApplicationRuntime.resolveVariables(String s) is invoked. The method replaces the runtime variables found in the given string with values provided by the runtime. If no corresponding value is found, or in other words, the variable cannot be resolved, no replacement is made, the variable is left in the ${var_name} format.
The variables are resolved by the runtime with getValue(String variableName) method. If the runtime has a value for the specific variable, it will return a non-null string value. If the variable cannot be resolved, the method will return null. The method must be overridden by subclasses, the default implementation does not resolve any variable.
TODO: The io.novaordis.clad.variable package is under development at the time of the writing. When it is done, update this paragraph.
Since clad was written, variable support has evolved in novaordis-utilities, if in the position to edit this paragraph, sync with novaordis-utilities Generic Variable System