II. Jakarta Commons CLI▲
Téléchargement▲
Jakarta Commons CLI est disponible ici, et nécessite Jakarta Commons Lang, disponible ici, pour fonctionner.
Commons CLI est, bien sûr, sous licence Apache.
Dans le cas où vous utilisez Maven comme outil de gestion de projet, il vous suffit d'ajouter cette dépendance dans votre fichier Pom :
<dependencies>
<dependency>
<groupId>
commons-cli</groupId>
<artifactId>
commons-cli</artifactId>
<version>
1.0</version>
</dependency>
</dependencies>
Et dans le cas de Maven 1, la dépendance Commons Lang est nécessaire :
<dependencies>
<dependency>
<groupId>
commons-lang</groupId>
<artifactId>
commons-lang</artifactId>
<version>
1.0</version>
</dependency>
</dependencies>
Définition des options▲
La première phase dans Commons CLI est de définir les arguments possibles. Durant cette étape, nous allons aussi bien définir des arguments optionnels, qu'obligatoires.
Certains arguments nécessiteront d'avoir une valeur (le numéro de port, le chemin vers le fichier de log), et un type associé à celle-ci (ex. : un entier pour le port).
Dans Commons CLI, un argument est représenté par une Option, elle-même stockée dans une classe Options qui représente la collection des Option que l'API devra pouvoir gérer.
Une Option possède plusieurs propriétés :
- un nom court, par exemple v dans le cas de l'argument de version, qui sera représenté par -v ;
- un nom long, par exemple version dans le cas de l'argument de version, qui sera représenté par –version ;
- une description, qui sera affichée dans l'aide ;
- un nom d'argument, qui sera affiché dans l'aide ;
- un flag booléen qui définit si une Option est obligatoire ;
- un flag booléen qui définit si une Option possèdera une valeur ou non ;
- si oui, un champ pour stocker cette valeur ;
- si oui, un champ pour définir le type d'objet que représente cette valeur ;
Afin de prendre en compte un ensemble d'Option, l'API fournit la classe Options :
Options options =
new
Options
(
);
Maintenant que nous avons un conteneur pour nos classes Option, il faut les créer, et pour cela il existe trois possibilités :
- via le constructeur ;
- via la classe OptionBuilder ;
- via une méthode de la classe Options.
Création via constructeur▲
La première est d'utiliser simplement les différents constructeurs fournis par la classe :
Option
(
String nomCourt, boolean
possedeArgument, String description)
Option
(
String nomCourt, String description)
Option
(
String nomCourt, String nomLong, boolean
possedeArgument, String description);
Ceux-ci créent une Option simple, qui est optionnelle, avec ou sans valeur. Il est ensuite possible d'utiliser les accesseurs pour paramétrer avec plus de détail l'Option :
Option port =
new
Option
(
"p"
, "port"
, true
, "Le port sur lequel le serveur doit écouter"
);
// Spécification du nom du paramètre de l'argument qui sera affiché dans l'aide
port.setArgName
(
"port"
);
// Spécification du type d'objet que retournera getValue, ici un Number vu que c'est un port
port.setType
(
Number.class
);
// Oblige le paramètre d'être présent lors de l'exécution
port.setRequired
(
true
);
// On ajoute ensuite l'Option dans la collection
options.add
(
port);
Dans le cas de l'option du port, vous vous demandez peut-être pourquoi utiliser un Number et non pas directement un Integer. Simplement que l'Integer n'est pas géré directement, mais Commons CLI va utiliser la classe NumberUtils de Commons Lang.
Cette classe va, selon le contenu de la variable, générer soit un Integer, soit un Float.
Création grâce à OptionBuilder▲
La deuxième méthode pour créer une option est d'utiliser OptionBuilder, celle-ci aide à la création d'Option. Toutes les méthodes sont statiques, et permettent de paramétrer une option, qui sera réellement instanciée lors de l'appel de la méthode statique create(String nomOpt).
// Spécification du nom du paramètre de l'argument
OptionBuilder.withArgName
(
"file"
);
// Spécification du nom long
OptionBuilder.withLongOpt
(
"logfile"
);
// Spécification du type de retour de la valeur du paramètre, ici c'est un fichier
OptionBuilder.withType
(
File.class
);
// Spécification de la description
OptionBuilder.withDescription
(
"Le fichier de log"
);
// Spécification de l'existence d'un paramètre à l'argument
OptionBuilder.hasArg
(
);
// Crée l'argument en lui passant un nom court
Option logfile =
OptionBuilder.create
(
"l"
);
// Ajout de l'Option dans la collection
options.add
(
logfile);
Via une méthode de la classe Options▲
Dans ces cas simples, il existe deux méthodes directement dans la classe Options.
public
Options addOption
(
String opt, boolean
hasArg, String description)
public
Options addOption
(
String opt, String longOpt, boolean
hasArg, String description)
C'est pratique dans le cas d'une option simple booléenne (j'existe ou pas), telle que l'option d'affichage de l'aide ou de la version :
options.addOption
(
"v"
, "version"
, false
, "Affiche la version du serveur"
);
options.addOption
(
"h, false, "
Affiche l'aide");
Analyse de la ligne de commande▲
La deuxième étape dans l'utilisation de l'API CLI est l'analyse de la ligne de commande, et cela se fait grâce à une implémentation de l'interface CommandLineParser. Commons CLI fournit deux implémentations de celle-ci :
- PosixParser : qui ne gère que des options à un seul caractère ( -v ou -h ) ;
- GnuParser : qui gère en plus les options à plusieurs caractères ( --version, --help ).
L'interface CommandLineParser possède deux méthodes :
public
CommandLine parse
(
Options options, String[] arguments )
throws
ParseException;
public
CommandLine parse
(
Options options, String[] arguments, boolean
stopAtNonOption )
throws
ParseException
Le premier paramètre de ces méthodes est la collection d'options qui a été créée précédemment, le second est le tableau d'arguments qui est fourni par la méthode public static void main(String args). Le troisième argument spécifie comment doit réagir le parseur lorsqu'il rencontre une option non définie.
Si l'on passe la valeur true, alors il arrêtera le traitement de la ligne, mais les arguments qui ont déjà été traités sont tout de même gardés. Dans le cas contraire, une UnrecognizedOptionException sera lancée.
Cette méthode peut aussi lancer une exception MissingOptionException lorsqu'une option obligatoire n'est pas présente, ou une MissingArgumentException dans le cas où une option nécessitant une valeur et que celle-ci n'est pas présente.
Utilisation▲
Le résultat du traitement est un objet CommandLine. L'utilisation de celui-ci se fait via quelques méthodes :
Methode |
Description |
---|---|
public boolean hasOption(String opt) |
Renvoie vrai si l'argument opt existe dans la ligne de commande |
public String getOptionValue( String opt ) |
Renvoie la valeur de l'argument sous forme de String |
public Object getOptionObject( String opt ) { |
Renvoie la valeur de l'argument sous forme d'instance d'un objet du type spécifié dans l'Option correspondante (ex. : un File dans le cas du fichier de log). Si cela n'est pas possible, renvoie null |
Le lanceur de MonServeur pourrait ressembler à ceci :
try
{
CommandLine cmd =
parser.parse
(
options, args, false
);
if
(
cmd.hasOption
(
"help"
)){
// Affiche l'aide
}
if
(
cmd.hasOption
(
"version"
)){
System.out.println
(
"MonServeur, version 0.1a"
);
}
Integer port =
(
Integer) cmd.getOptionObject
(
"port"
);
File logfile =
(
File) cmd.getOptionObject
(
"logfile"
) ;
MonServer server =
new
MonServeur
(
port, logfile);
}
catch
(
ParseException e) {
// Affichage de l'aide
}
Reste maintenant à afficher l'aide, ou l'usage du lanceur, et pour cela l'API fournit une méthode très simple :
HelpFormatter formatter =
new
HelpFormatter
(
);
formatter.printHelp
(
"MonServeur"
, options);
La classe HelpFormater fournit la méthode printHelp, dont le premier paramètre est le nom de l'exécutable en lui-même (qui pourrait être remplacé par « MonServeur.exe » si l'on utilisait un outil tel que exe4j). Le second est tout simplement les options définies.
Utilisation avancée▲
En plus des arguments booléens simples, ou même avec valeurs, l'API fournit un moyen de spécifier que certaines options ne peuvent pas être présentes en même temps que d'autres.
Par exemple, il ne devrait pas être possible d'afficher à la fois la version, l'aide, et de lancer le programme. Ces trois options doivent être exclusives, si l'une est présente, aucune des deux autres ne doit l'être.
Cette responsabilité est gérée par la classe OptionGroup, qui est aussi un conteneur d'Option, mais est aussi contenue dans le conteneur Options.
// Abandon de la création des options par la méthode d'Options au profit de la version via constructeurs
Option help =
new
Option
(
ARGUMENT_HELP_SHORT, false
, "Affiche l'aide"
);
Option version =
new
Option
(
ARGUMENT_VERSION_SHORT, false
, "Affiche la version"
);
// Création du groupe d'options
OptionGroup group =
new
OptionGroup
(
);
// Ajout des options exclusives
group.addOption
(
help) ;
group.addOption
(
version);
group.addOption
(
port);
// Possibilité de rendre un groupe obligatoire
group.setRequired
(
true
);
// Ajout du groupe dans le conteneur Options
options.addOptionGroup
(
group);
Annexes▲
Listes des exceptions lancées par la méthode CommandLineParser.parse▲
Exception |
Cause |
---|---|
MissingOptionException |
Un argument obligatoire n'a pas été fourni dans la ligne de commande |
MissingArgumentException |
Une valeur obligatoire pour un argument n'a pas été fournie |
AlreadySelectedException |
Plus d'une option d'un même groupe d'options exclusives a été fournie |
UnrecognizedOptionException |
Un argument qui n'a pas été déclaré dans les options possibles a été fourni |
Types de valeurs gérées pour un argument▲
Classe |
Description |
---|---|
File.class |
Renvoie un objet File(<valeur de l'argument>) |
Number.class |
Renvoie un Integer s’il n'y a pas de virgule dans la valeur de l'argument. |
Class.class |
Renvoie une classe via Class.forName(<valeur de l'argument>) |
Object.class |
Tente d'instancier un objet de la classe <valeur de l'argument> |
Url.class |
Renvoie une URL(<valeur de l'argument>) |
Date.class |
Devrait renvoyer une Date, mais n'est pas implémentée dans la version stable |