Lancer un programme avec des paramètres, avec Common CLI, en 5 minutes

Dans ce court tutoriel, nous allons voir comment utiliser la bibliothèque Common CLI pour gérer les paramètres d'entrée de vos programmes Java. Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnelICAUDA

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

La plupart des programmes qu'on écrit ont besoin de paramètres en entrée. En java, c'est relativement simple de les gérer, mais c'est toujours un peu rébarbatif. Dans ce tutoriel, nous allons voir que cette tâche peut être finalement assez simple et rapide à l'aide d'une bibliothèque comme Common CLI.

Les codes sources complets des classes importantes sont proposés en annexe.

I-A. Avant de commencer

Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :

  • JDK 1.8.0_45 ;
  • Eclipse 4.6 (Neon) ;
  • Apache Common CLI 1.3.1.

II. Découverte du projet d'exemple

II-A. Télécharger, installer et importer le projet d'exemple

Durée estimée : 1 minute.

Pour commencer, je vous propose de télécharger le fichier Zip article-common-cli-5-min-01.zip, contenant un projet Java-Maven d'exemple.

Compilez le projet d'exemple et importez-le dans votre IDE favori.

Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexe).

II-B. Fibonacci

Il fallait un exemple pour illustrer cet article. Je vous propose d'utiliser la suite de Fibonacci que vous ne connaissez sans doute que trop bien. Si ce n'est pas le cas, je vous invite à consulter la page Wikipédia consacrée à la suite de Fibonacci.

Le projet contient plusieurs algorithmes pour calculer les membres de la suite de Fibonacci ainsi que les tests unitaires qui vont de paire. Jetez-y un œil par curiosité, mais ne vous attardez pas trop sur les bogues. Ces classes implémentent l'interface FibonacciCalculator suivante :

Interface FibonacciCalculator.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.

public interface FibonacciCalculator {

    /**
     * Calcule la valeur du membre de la suite de Fibonacci pour le rang n.
     * 
     * @param n
     *            rang positif
     * @return valeur du membre pour le rand indiqué.
     * @throws IllegalArgumentException
     *             si le rang est négatif
     */
    long calculate(final int n);

II-C. Ce qui est déjà dans l'exemple

Le programme d'exemple est une simple classe dotée d'une méthode main(). Les paramètres de configuration (algorithme, rang, timer, verbose) des algorithmes de calcul sont directement codés dans la méthode main() :

Classe Fibo.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.

public class Fibo {

    public static void main(String[] args) {

        // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)
        char algo = 'i';

        // Rang
        int n = 42;

        // Timer
        boolean timerMode = false;

        // Verbose
        boolean verboseMode = true;

        if (verboseMode) {
            timerMode = true;
        }

        // Calculator
        FibonacciCalculator calc = null;
        String algoName = null;
        switch (algo) {
            // recursif (r)
            case 'r':
                calc = new RecursifFibonnacciCalculator();
                algoName = "Recursif";
                break;

            ...
        }

        if (verboseMode) {
            System.out.println("Calculating Fibonacci for n: " + n);
            System.out.println("Selected algorithm: " + algoName);
        }

        final long time1 = System.currentTimeMillis();

        final long result = calc.calculate(n);

        final long time2 = System.currentTimeMillis();

        if (timerMode) {
            System.out.println("Duration: " + (time2 - time1) + " ms");
        }

        if (verboseMode) {
            System.out.println("Fibonacci(" + n + ")=" + result);
        }

        System.out.println(result);
    }
}

Vous excuserez les println de ce bout de code… Ils seront largement suffisants pour ce qu'on a à voir.

Quand on lance l'application, on doit avoir un affichage ressemblant au bloc suivant :

Console
Sélectionnez

Calculating Fibonacci for n: 42
Selected algorithm: Iteratif
Duration: 0 ms
Fibonacci(42)=433494437
433494437

III. À la main

Durée estimée : 2 minutes.

On voudrait pouvoir lancer le programme et lui passer des arguments comme dans l'exemple suivant :

Console
Sélectionnez

FiboManual --algo=r --rang=42 --timer=true --verbose=true

Il est facile de coder une première version naïve pour utiliser les valeurs passées en paramètre au lancement du programme. Je vous propose d'utiliser une HashMap toute simple :

Traitement des paramètres dans FiboManual.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.

private static Map<String, String> parseParameters(final String[] args) {

    final Map<String, String> parameters = new HashMap<>();

    for (final String arg : args) {
        if (!arg.startsWith("--")) {
            System.err.println("Bad parameter: " + arg);
            System.exit(2);
        }

        final String[] tab = arg.substring(2).split("=");
        parameters.put(tab[0], tab[1]);
    }

    return parameters;
}

Cette méthode a l'avantage de traiter les paramètres sans imposer ni d'ordre ni de présence. Dans une vraie version, on pensera à gérer les exceptions.

Il suffit d'appeler la méthode pour traiter les paramètres :

Appel du traitement des paramètres dans FiboManual.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.

public class FiboManual {

    public static void main(final String[] args) {

        final Map<String, String> parameters = parseParameters(args);

        ...

Pour utiliser les valeurs, il suffit de les prendre depuis la map :

Utilisation des paramètres dans FiboManual.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.

final Map<String, String> parameters = parseParameters(args);

// Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)
char algo = 'i';
final String algoFromParamaters = parameters.get("algo");
if (algoFromParamaters != null) {
    algo = algoFromParamaters.charAt(0);
}

// Rang
final String rangFromParamaters = parameters.get("rang");
int n = 0;
try {
    n = Integer.valueOf(rangFromParamaters);
} catch (Exception e) {
    System.err.println("Bad parameter: algo");
    System.exit(3);
}

// Timer
boolean timerMode = false;
final String timerFromParamaters = parameters.get("timer");
if(timerFromParamaters != null) {
    timerMode = timerFromParamaters.equalsIgnoreCase("true");
}

// Verbose
boolean verboseMode = true;
final String verboseFromParamaters = parameters.get("verbose");
if(verboseFromParamaters != null) {
    verboseMode = verboseFromParamaters.equalsIgnoreCase("true");
}

Le code du projet à ce stade est disponible dans le fichier article-common-cli-5-min-02.zip

On voit bien qu'une bonne partie du code va se répéter dans tous les exemples de ce tutoriel. On va donc le factoriser un peu dans une classe abstraite :

Classe abstraite AbstractFibo.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.

public abstract class AbstractFibo {

    protected static void work(final int n, final FibonacciCalculator calc, final boolean timerMode, final boolean verboseMode) {
        if (verboseMode) {
            System.out.println("Calculating Fibonacci for n: " + n);
            System.out.println("Selected algorithm: " + calc.getName());
        }

        final long time1 = System.currentTimeMillis();

        final long result = calc.calculate(n);

        final long time2 = System.currentTimeMillis();

        if (timerMode) {
            System.out.println("Duration: " + (time2 - time1) + " ms");
        }

        if (verboseMode) {
            System.out.println("Fibonacci(" + n + ")=" + result);
        }

        System.out.println(result);
    }

    protected static FibonacciCalculator getCalculator(final char algo) {
        switch (algo) {
            // recursif (r)
            case 'r':
                return new RecursifFibonnacciCalculator();

            ...
        }

        return null;
    }
}

Du coup, le code de l'exemple se simplifie comme suit :

Simplification de FiboManual.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.

public class FiboManual extends AbstractFibo {

    public static void main(final String[] args) {

        ...

        // Calculator
        final FibonacciCalculator calc = getCalculator(algo);

        // Work
        work(n, calc, timerMode, verboseMode);
    }

Le code du projet à ce stade est disponible dans le fichier article-common-cli-5-min-03.zip

Ce code n'est pas très difficile à écrire, mais on en voit bien les limites.

IV. Action avec Common CLI

La bibliothèque Common CLI va nous permettre d'aller plus loin et plus vite. Pour commencer, plutôt que de passer les arguments sous la forme « key=value », on voudrait utiliser le même format que sous Linux :

Console
Sélectionnez

FiboCli --algo r --rang 42 --timer --verbose

ou en raccourci :

Console
Sélectionnez

FiboCli -a r -r 42 -t -v

ou même un mélange :

Console
Sélectionnez

FiboCli --algo -r --rang 42 -t -v

Vous remarquez que certains paramètres, comme « -v » pour « verbose », n'ont pas de valeur. Quand le paramètre est présent, sa valeur vaut implicitement « true », ce qui est bien pratique et plus simple.

IV-A. Ajout d'Apache Common CLI

Durée estimée : 1 minute.

Pour profiter de la bibliothèque « Apache Common CLI », vous devez ajouter des dépendances dans le fichier « pom.xml » :

pom.xml
Sélectionnez
1.
2.
3.
4.
5.
6.

<dependency>
    <groupId>commons-cli</groupId>
    <artifactId>commons-cli</artifactId>
    <version>1.3.1</version>
</dependency>

IV-B. Configuration

Durée estimée : 1 minute.

Pour faire simple, la définition d'un paramètre ressemble au code suivant :

Option
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.

Option algoFileOption = Option.builder("a") 
    .longOpt("algo") 
    .desc("Bla bla bla") 
    .hasArg(true) 
    .argName("algo") 
    .required(false) 
    .build();

Dans notre cas, on va donc écrire quatre blocs, correspondant aux quatre options de lancement :

Configuration des paramètres dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.

private static Options configParameters() {

    final Option algoFileOption = Option.builder("a") 
            .longOpt("algo") //
            .desc("Algorithm: recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)") 
            .hasArg(true) 
            .argName("algo")
            .required(false) 
            .build();

    final Option rangFileOption = Option.builder("r") 
            .longOpt("rang") 
            .desc("Rang") 
            .hasArg(true) 
            .argName("numeric") 
            .required(true) 
            .build();

    final Option timerFileOption = Option.builder("t") 
            .longOpt("timer") 
            .desc("Timer") 
            .hasArg(false) 
            .required(false) 
            .build();

    final Option verboseFileOption = Option.builder("v") 
            .longOpt("verbose") 
            .desc("Verbose") 
            .hasArg(false) 
            .required(false) 
            .build();

    final Options options = new Options();

    options.addOption(algoFileOption);
    options.addOption(rangFileOption);
    options.addOption(timerFileOption);
    options.addOption(verboseFileOption);

    return options;
}

L'ordre de déclaration des options n'a pas d'importance.

IV-C. Utilisation

Durée estimée : 2 minutes.

Une fois qu'on a défini les options, il faut parser les paramètres. Il existe plusieurs parsers, mais celui par défaut fera bien l'affaire dans le cadre de ce tutoriel :

Traitement des paramètres dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.

final Options options = configParameters();

final CommandLineParser parser = new DefaultParser();
final CommandLine line = parser.parse(options, args);

Ensuite, on utilisera surtout line.getOptionValue(..) et line.hasOption(..) pour récupérer les valeurs.

Utilisation dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.

public class FiboCli extends AbstractFibo {

    public static void main(final String[] args) throws ParseException {

        final Options options = configParameters();

        final CommandLineParser parser = new DefaultParser();
        final CommandLine line = parser.parse(options, args);

        // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)
        char algo = line.getOptionValue("algo", "i").charAt(0);

        // Rang
        final String rangFromParamaters = line.getOptionValue("rang", "");
        int n = 0;
        try {
            n = Integer.valueOf(rangFromParamaters);
        } catch (Exception e) {
            System.err.println("Bad parameter: algo");
            System.exit(3);
        }

        // Timer
        boolean timerMode = line.hasOption("timer");

        // Verbose
        boolean verboseMode = line.hasOption("verbose");

        if (verboseMode) {
            timerMode = true;
        }

IV-D. Option --help

Durée estimée : 5 minutes (il y a un piège).

On va aller un peu plus loin en ajoutant l'option de lancement permettant d'afficher l'aide.

Option d'aide dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.

final Option helpFileOption = Option.builder("h") 
    .longOpt("help") 
    .desc("Affiche le message d'aide") 
    .build();

On ne va pas pouvoir ajouter simplement cette option à la liste d'options ; il y a un piège. En effet, on veut que l'aide s'affiche lorsqu'on utilise l'option « -h » et que le programme s'arrête. Or l'option d'aide est facultative alors que d'autres options, comme le choix du rang, sont obligatoires. Il faut donc mettre en place une petite mécanique.

Pour commencer, il faut définir deux groupes d'options. On mettra l'option d'aide dans le premier :

Option d'aide dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.

private static Options configFirstParameters() {

    final Option helpFileOption = Option.builder("h") 
            .longOpt("help") 
            .desc("Affiche le message d'aide") 
            .build();

    final Options firstOptions = new Options();

    firstOptions.addOption(helpFileOption);

    return firstOptions;
}

Et on pourra recopier les options du premier groupe vers le second :

Toutes les options dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.

private static Options configParameters(final Options firstOptions) {

    ...

    final Options options = new Options();

    // First Options
    for (final Option fo : firstOptions.getOptions()) {
        options.addOption(fo);
    }

    // All other options
    options.addOption(algoFileOption);
    options.addOption(rangFileOption);
    options.addOption(timerFileOption);
    options.addOption(verboseFileOption);

    return options;
}

Au niveau de la méthode main(), il n'y a qu'à enchaîner les deux appels :

Les options dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.

public class FiboCli extends AbstractFibo {

    public static void main(final String[] args) throws ParseException {

        // Options
        final Options firstOptions = configFirstParameters();
        final Options options = configParameters(firstOptions);

L'idée, dans un premier temps, est de ne parser que le premier groupe.

Les options dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.

// Options
final Options firstOptions = configFirstParameters();
final Options options = configParameters(firstOptions);

// On parse l'aide
final CommandLineParser parser = new DefaultParser();
final CommandLine firstLine = parser.parse(firstOptions, args, true);

Le dernier argument de la méthode parse(), ici avec la valeur « true », permet de dire au parser de ne pas s'arrêter si on lui passe des options qu'il ne connaît pas.

Pour afficher l'aide, on doit utilise la méthode printHelp() de HelpFormatter et on quitte simplement :

Affichage de l'aide dans FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.

// Si mode aide
boolean helpMode = firstLine.hasOption("help");
if (helpMode) {
    final HelpFormatter formatter = new HelpFormatter();
    formatter.printHelp("FiboCLI", options, true);
    System.exit(0);
}

Le reste du code ne change pas. Voici à quoi doit ressembler l'aide :

Console
Sélectionnez

FiboCLI -h

usage: FiboCLI [-a <algo>] [-h] -r <numeric> [-t] [-v]
 -a,--algo <algo>      Algorithm: recursif (r) / memoization (m) /
                       terminal (t) / iteratif (i) / direct (d)
 -h,--help             Affiche le message d'aide
 -r,--rang <numeric>   Rang
 -t,--timer            Timer
 -v,--verbose          Verbose

Le code du projet à ce stade est disponible dans le fichier article-common-cli-5-min-04.zip

V. Conclusion

Allez, comme d'habitude, on a déjà bien dépassé le contrat des « 5 minutes »". On va s'arrêter là, car c'est largement suffisant pour comprendre comment fonctionne la bibliothèque Apache Common CLI. Vous avez pu constater que c'est relativement simple.

Bien entendu, les fonctionnalités que nous avons découvertes sont relativement simples et CLI sait faire bien plus que cela. Nous avons néanmoins vu celles qui me semblent être les plus importantes et que vous utiliserez à coup sûr dans vos projets. Vous avez toutes les cartes en main. Par exemple, on aurait aussi pu mettre en place un builder, éventuellement générique, pour lire et traiter les paramètres au lieu de tout faire dans le main.

Dans le même goût, on peut aussi s'intéresser à la bibliothèque owner qui permet de gérer les propriétés de configuration depuis un fichier.

Vos retours nous aident à améliorer nos publications. N'hésitez donc pas ? commenter cet article sur le forum : Commentez Donner une note à l'article (5)

VI. Remerciements

D'abord j'adresse mes remerciements à l'équipe CLI, chez Apache, pour avoir développé une bibliothèque aussi utile. Je n'oublie pas tous les contributeurs qui participent notamment sur le forum.

Plus spécifiquement en ce qui concerne cet article, je tiens à remercier l'équipe de Developpez.com et plus particulièrement Mickael Baron et Milkoseck.

VII. Annexes

VII-A. Liens

VII-B. Liens personnels

Retrouvez ma page et mes autres articles sur Developpez.com à l'adresse:
http://thierry-leriche-dessirier.developpez.com/#page_articles.

Suivez-moi sur Twitter : @thierrylerichehttps://twitter.com/thierryleriche

et sur mon site/blog ICAUDA : http://www.icauda.com.

VII-C. Codes sources complets

AbstractFibo.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.

package com.icauda.article.commoncli;

import com.icauda.article.commoncli.fibonacci.DirectFibonacciCalculator;
import com.icauda.article.commoncli.fibonacci.FibonacciCalculator;
import com.icauda.article.commoncli.fibonacci.IteratifFibonacciCalculator;
import com.icauda.article.commoncli.fibonacci.MemoizationFibonnacciCalculator;
import com.icauda.article.commoncli.fibonacci.RecursifFibonnacciCalculator;
import com.icauda.article.commoncli.fibonacci.TerminalFibonnacciCalculator;

public abstract class AbstractFibo {

    protected static void work(final int n, final FibonacciCalculator calc, final boolean timerMode, final boolean verboseMode) {
        if (verboseMode) {
            System.out.println("Calculating Fibonacci for n: " + n);
            System.out.println("Selected algorithm: " + calc.getName());
        }

        final long time1 = System.currentTimeMillis();

        final long result = calc.calculate(n);

        final long time2 = System.currentTimeMillis();

        if (timerMode) {
            System.out.println("Duration: " + (time2 - time1) + " ms");
        }

        if (verboseMode) {
            System.out.println("Fibonacci(" + n + ")=" + result);
        }

        System.out.println(result);
    }

    protected static FibonacciCalculator getCalculator(final char algo) {
        switch (algo) {
            // recursif (r)
            case 'r':
                return new RecursifFibonnacciCalculator();

            // memoization (m)
            case 'm':
                return new MemoizationFibonnacciCalculator();

            // terminal (t)
            case 't':
                return new TerminalFibonnacciCalculator();

            // iteratif (i)
            case 'i':
                return new IteratifFibonacciCalculator();

            // direct (d)
            case 'd':
                return new DirectFibonacciCalculator();

            default:
                System.err.println("Algo inconnu: " + algo);
                System.exit(1);
        }

        return null;
    }
}
Fibo.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.

package com.icauda.article.commoncli;

import com.icauda.article.commoncli.fibonacci.FibonacciCalculator;

public class Fibo extends AbstractFibo {

    public static void main(String[] args) {

        // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)
        char algo = 'i';

        // Rang
        int n = 42;

        // Timer
        boolean timerMode = false;

        // Verbose
        boolean verboseMode = true;

        if (verboseMode) {
            timerMode = true;
        }

        // Calculator
        final FibonacciCalculator calc = getCalculator(algo);

        // Work
        work(n, calc, timerMode, verboseMode);
    }
}
FiboManual.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.

package com.icauda.article.commoncli;

import java.util.HashMap;
import java.util.Map;

import com.icauda.article.commoncli.fibonacci.FibonacciCalculator;

/*
 * Usage FiboManual --algo=r --rang=42 --timer=true --verbose=true
 */
public class FiboManual extends AbstractFibo {

    public static void main(final String[] args) {

        final Map<String, String> parameters = parseParameters(args);

        // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)
        char algo = 'i';
        final String algoFromParamaters = parameters.get("algo");
        if (algoFromParamaters != null) {
            algo = algoFromParamaters.charAt(0);
        }

        // Rang
        final String rangFromParamaters = parameters.get("rang");
        int n = 0;
        try {
            n = Integer.valueOf(rangFromParamaters);
        } catch (Exception e) {
            System.err.println("Bad parameter: algo");
            System.exit(3);
        }

        // Timer
        boolean timerMode = false;
        final String timerFromParamaters = parameters.get("timer");
        if (timerFromParamaters != null) {
            timerMode = timerFromParamaters.equalsIgnoreCase("true");
        }

        // Verbose
        boolean verboseMode = true;
        final String verboseFromParamaters = parameters.get("verbose");
        if (verboseFromParamaters != null) {
            verboseMode = verboseFromParamaters.equalsIgnoreCase("true");
        }

        if (verboseMode) {
            timerMode = true;
        }

        // Calculator
        final FibonacciCalculator calc = getCalculator(algo);

        // Work
        work(n, calc, timerMode, verboseMode);
    }

    private static Map<String, String> parseParameters(final String[] args) {

        final Map<String, String> parameters = new HashMap<>();

        for (final String arg : args) {
            if (!arg.startsWith("--")) {
                System.err.println("Bad parameter: " + arg);
                System.exit(2);
            }

            final String[] tab = arg.substring(2).split("=");
            parameters.put(tab[0], tab[1]);
        }

        return parameters;
    }
}
FiboCli.java
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.

package com.icauda.article.commoncli;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import com.icauda.article.commoncli.fibonacci.FibonacciCalculator;

/*
 * Usage FiboCli --algo r --rang 42 --timer --verbose
 *               -a       -r        -t      -v
 */
public class FiboCli extends AbstractFibo {

    public static void main(final String[] args) throws ParseException {

        // Options
        final Options firstOptions = configFirstParameters();
        final Options options = configParameters(firstOptions);

        // On parse l'aide
        final CommandLineParser parser = new DefaultParser();
        final CommandLine firstLine = parser.parse(firstOptions, args, true);

        // Si mode aide
        boolean helpMode = firstLine.hasOption("help");
        if (helpMode) {
            final HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp("FiboCLI", options, true);
            System.exit(0);
        }

        // On parse la suite
        final CommandLine line = parser.parse(options, args);

        // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)
        char algo = line.getOptionValue("algo", "i").charAt(0);

        // Rang
        final String rangFromParamaters = line.getOptionValue("rang", "");
        int n = 0;
        try {
            n = Integer.valueOf(rangFromParamaters);
        } catch (Exception e) {
            System.err.println("Bad parameter: algo");
            System.exit(3);
        }

        // Timer
        boolean timerMode = line.hasOption("timer");

        // Verbose
        boolean verboseMode = line.hasOption("verbose");

        if (verboseMode) {
            timerMode = true;
        }

        // Calculator
        final FibonacciCalculator calc = getCalculator(algo);

        // Work
        work(n, calc, timerMode, verboseMode);
    }

    private static Options configFirstParameters() {

        final Option helpFileOption = Option.builder("h") //
                .longOpt("help") //
                .desc("Affiche le message d'aide") //
                .build();

        final Options firstOptions = new Options();

        firstOptions.addOption(helpFileOption);

        return firstOptions;

    }

    private static Options configParameters(final Options firstOptions) {

        final Option algoFileOption = Option.builder("a") //
                .longOpt("algo") //
                .desc("Algorithm: recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)") //
                .hasArg(true) //
                .argName("algo") //
                .required(false) //
                .build();

        final Option rangFileOption = Option.builder("r") //
                .longOpt("rang") //
                .desc("Rang") //
                .hasArg(true) //
                .argName("numeric") //
                .required(true) //
                .build();

        final Option timerFileOption = Option.builder("t") //
                .longOpt("timer") //
                .desc("Timer") //
                .hasArg(false) //
                .required(false) //
                .build();

        final Option verboseFileOption = Option.builder("v") //
                .longOpt("verbose") //
                .desc("Verbose") //
                .hasArg(false) //
                .required(false) //
                .build();

        final Options options = new Options();

        // First Options
        for (final Option fo : firstOptions.getOptions()) {
            options.addOption(fo);
        }

        // All other options
        options.addOption(algoFileOption);
        options.addOption(rangFileOption);
        options.addOption(timerFileOption);
        options.addOption(verboseFileOption);

        return options;
    }
}

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2016 Thierry-Leriche-Dessirier. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.