Comparaison de Jakarta Commons CLI et Args4j


précédentsommairesuivant

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 :

 
Sélectionnez
<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 :

 
Sélectionnez
<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 necéssiteront 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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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'object 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 ajout 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).

 
Sélectionnez

// 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.

 
Sélectionnez

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 :

 
Sélectionnez

options.addOption("v", "version", false, "Affiche la version du serveur");
options.addOption("h, false, "Affiche l'aide");

Analyse de la ligne de commandes

La deuxième étape dans l'utilisation de l'API CLI est l'analyse de la ligne de commandes, 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 :

 
Sélectionnez

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'option 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éja é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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 meme 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 doivent l'être.

Cette responsabilité est gérée par la classe OptionGroup, qui est aussi un conteneur d'Option, mais est aussi contenu dans le conteneur Options.

 
Sélectionnez

// Abandon de la creation 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");

// Creation du groupe d'option
OptionGroup group = new OptionGroup();
// Ajout des options exclusives
group.addOption(help) ;
group.addOption(version);
group.addOption(port);

// Possibilite 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é fourni
AlreadySelectedException Plus d'une option d'un même groupe d'options exclusives a été fourni
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 si il n'y a pas de virgule dans la valeur de l'argument.
Sinon renvoie un Float
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 un URL(<valeur de l'argument>)
Date.class Devrait renvoyer une Date, mais n'est pas implémenté dans la version stable

précédentsommairesuivant

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.