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

Thierry-Leriche-Dessirier

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

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

- Auteur : Thierry-Leriche-Dessirier

- Parution : 3 octobre 2016

- Licence : 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.

Sommaire

- I. Introduction

- I-A. Avant de commencer

- II. Découverte du projet d'exemple

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

- II-B. Fibonacci

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

- III. À la main

- IV. Action avec Common CLI

- IV-A. Ajout d'Apache Common CLI

- IV-B. Configuration

- IV-C. Utilisation

- IV-D. Option --help

- V. Conclusion

- VI. Remerciements

- VII. Annexes

- VII-A. Liens

- VII-B. Liens personnels

- VII-C. Codes sources complets

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

1. public interface FibonacciCalculator {

3. /**

4. * Calcule la valeur du membre de la suite de Fibonacci pour le rang n.

5. *

6. * @param n

7. *            rang positif

8. * @return valeur du membre pour le rand indiqué.

9. * @throws IllegalArgumentException

10. *             si le rang est négatif

11. */

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

1. public class Fibo {

3. public static void main(String[] args) {

5. // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)

6. char algo = 'i';

8. // Rang

9. int n = 42;

11. // Timer

12. boolean timerMode = false;

14. // Verbose

15. boolean verboseMode = true;

17. if (verboseMode) {

18. timerMode = true;

19. }

21. // Calculator

22. FibonacciCalculator calc = null;

23. String algoName = null;

24. switch (algo) {

25. // recursif (r)

26. case 'r':

27. calc = new RecursifFibonnacciCalculator();

28. algoName = "Recursif";

29. break;

31. ...

32. }

34. if (verboseMode) {

35. System.out.println("Calculating Fibonacci for n: " + n);

36. System.out.println("Selected algorithm: " + algoName);

37. }

39. final long time1 = System.currentTimeMillis();

41. final long result = calc.calculate(n);

43. final long time2 = System.currentTimeMillis();

45. if (timerMode) {

46. System.out.println("Duration: " + (time2 - time1) + " ms");

47. }

49. if (verboseMode) {

50. System.out.println("Fibonacci(" + n + ")=" + result);

51. }

53. System.out.println(result);

54. }

55. }

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

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

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

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

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

5. for (final String arg : args) {

6. if (!arg.startsWith("--")) {

7. System.err.println("Bad parameter: " + arg);

8. System.exit(2);

9. }

11. final String[] tab = arg.substring(2).split("=");

12. parameters.put(tab[0], tab[1]);

13. }

15. return parameters;

16. }

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

1. public class FiboManual {

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

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

7. ...

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

Utilisation des paramètres dans FiboManual.java

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

3. // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)

4. char algo = 'i';

5. final String algoFromParamaters = parameters.get("algo");

6. if (algoFromParamaters != null) {

7. algo = algoFromParamaters.charAt(0);

8. }

10. // Rang

11. final String rangFromParamaters = parameters.get("rang");

12. int n = 0;

13. try {

14. n = Integer.valueOf(rangFromParamaters);

15. } catch (Exception e) {

16. System.err.println("Bad parameter: algo");

17. System.exit(3);

18. }

20. // Timer

21. boolean timerMode = false;

22. final String timerFromParamaters = parameters.get("timer");

23. if(timerFromParamaters != null) {

24. timerMode = timerFromParamaters.equalsIgnoreCase("true");

25. }

27. // Verbose

28. boolean verboseMode = true;

29. final String verboseFromParamaters = parameters.get("verbose");

30. if(verboseFromParamaters != null) {

31. verboseMode = verboseFromParamaters.equalsIgnoreCase("true");

32. }

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

1. public abstract class AbstractFibo {

3. protected static void work(final int n, final FibonacciCalculator calc, final boolean timerMode, final boolean verboseMode) {

4. if (verboseMode) {

5. System.out.println("Calculating Fibonacci for n: " + n);

6. System.out.println("Selected algorithm: " + calc.getName());

7. }

9. final long time1 = System.currentTimeMillis();

11. final long result = calc.calculate(n);

13. final long time2 = System.currentTimeMillis();

15. if (timerMode) {

16. System.out.println("Duration: " + (time2 - time1) + " ms");

17. }

19. if (verboseMode) {

20. System.out.println("Fibonacci(" + n + ")=" + result);

21. }

23. System.out.println(result);

24. }

26. protected static FibonacciCalculator getCalculator(final char algo) {

27. switch (algo) {

28. // recursif (r)

29. case 'r':

30. return new RecursifFibonnacciCalculator();

32. ...

33. }

35. return null;

36. }

37. }

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

Simplification de FiboManual.java

1. public class FiboManual extends AbstractFibo {

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

5. ...

7. // Calculator

8. final FibonacciCalculator calc = getCalculator(algo);

10. // Work

11. work(n, calc, timerMode, verboseMode);

12. }

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

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

ou en raccourci :

Console

FiboCli -a r -r 42 -t -v

ou même un mélange :

Console

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

1. <dependency>

2. <groupId>commons-cli</groupId>

3. <artifactId>commons-cli</artifactId>

4. <version>1.3.1</version>

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

1. Option algoFileOption = Option.builder("a")

2. .longOpt("algo")

3. .desc("Bla bla bla")

4. .hasArg(true)

5. .argName("algo")

6. .required(false)

7. .build();

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

Configuration des paramètres dans FiboCli.java

1. private static Options configParameters() {

3. final Option algoFileOption = Option.builder("a")

4. .longOpt("algo") //

5. .desc("Algorithm: recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)")

6. .hasArg(true)

7. .argName("algo")

8. .required(false)

9. .build();

11. final Option rangFileOption = Option.builder("r")

12. .longOpt("rang")

13. .desc("Rang")

14. .hasArg(true)

15. .argName("numeric")

16. .required(true)

17. .build();

19. final Option timerFileOption = Option.builder("t")

20. .longOpt("timer")

21. .desc("Timer")

22. .hasArg(false)

23. .required(false)

24. .build();

26. final Option verboseFileOption = Option.builder("v")

27. .longOpt("verbose")

28. .desc("Verbose")

29. .hasArg(false)

30. .required(false)

31. .build();

33. final Options options = new Options();

35. options.addOption(algoFileOption);

36. options.addOption(rangFileOption);

37. options.addOption(timerFileOption);

38. options.addOption(verboseFileOption);

40. return options;

41. }

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

1. final Options options = configParameters();

3. final CommandLineParser parser = new DefaultParser();

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

1. public class FiboCli extends AbstractFibo {

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

5. final Options options = configParameters();

7. final CommandLineParser parser = new DefaultParser();

8. final CommandLine line = parser.parse(options, args);

10. // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)

11. char algo = line.getOptionValue("algo", "i").charAt(0);

13. // Rang

14. final String rangFromParamaters = line.getOptionValue("rang", "");

15. int n = 0;

16. try {

17. n = Integer.valueOf(rangFromParamaters);

18. } catch (Exception e) {

19. System.err.println("Bad parameter: algo");

20. System.exit(3);

21. }

23. // Timer

24. boolean timerMode = line.hasOption("timer");

26. // Verbose

27. boolean verboseMode = line.hasOption("verbose");

29. if (verboseMode) {

30. timerMode = true;

31. }

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

1. final Option helpFileOption = Option.builder("h")

2. .longOpt("help")

3. .desc("Affiche le message d'aide")

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

1. private static Options configFirstParameters() {

3. final Option helpFileOption = Option.builder("h")

4. .longOpt("help")

5. .desc("Affiche le message d'aide")

6. .build();

8. final Options firstOptions = new Options();

10. firstOptions.addOption(helpFileOption);

12. return firstOptions;

13. }

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

Toutes les options dans FiboCli.java

1. private static Options configParameters(final Options firstOptions) {

3. ...

5. final Options options = new Options();

7. // First Options

8. for (final Option fo : firstOptions.getOptions()) {

9. options.addOption(fo);

10. }

12. // All other options

13. options.addOption(algoFileOption);

14. options.addOption(rangFileOption);

15. options.addOption(timerFileOption);

16. options.addOption(verboseFileOption);

18. return options;

19. }

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

Les options dans FiboCli.java

1. public class FiboCli extends AbstractFibo {

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

5. // Options

6. final Options firstOptions = configFirstParameters();

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

1. // Options

2. final Options firstOptions = configFirstParameters();

3. final Options options = configParameters(firstOptions);

5. // On parse l'aide

6. final CommandLineParser parser = new DefaultParser();

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

1. // Si mode aide

2. boolean helpMode = firstLine.hasOption("help");

3. if (helpMode) {

4. final HelpFormatter formatter = new HelpFormatter();

5. formatter.printHelp("FiboCLI", options, true);

6. System.exit(0);

7. }

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

Console

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

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

Apache Common CLI : https://commons.apache.org/proper/commons-cli/

VII-B - Liens personnels

Retrouvez ma page et mes autres articles sur Developpez.com à l'adresse:
https://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

1. package com.icauda.article.commoncli;

3. import com.icauda.article.commoncli.fibonacci.DirectFibonacciCalculator;

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

5. import com.icauda.article.commoncli.fibonacci.IteratifFibonacciCalculator;

6. import com.icauda.article.commoncli.fibonacci.MemoizationFibonnacciCalculator;

7. import com.icauda.article.commoncli.fibonacci.RecursifFibonnacciCalculator;

8. import com.icauda.article.commoncli.fibonacci.TerminalFibonnacciCalculator;

10. public abstract class AbstractFibo {

12. protected static void work(final int n, final FibonacciCalculator calc, final boolean timerMode, final boolean verboseMode) {

13. if (verboseMode) {

14. System.out.println("Calculating Fibonacci for n: " + n);

15. System.out.println("Selected algorithm: " + calc.getName());

16. }

18. final long time1 = System.currentTimeMillis();

20. final long result = calc.calculate(n);

22. final long time2 = System.currentTimeMillis();

24. if (timerMode) {

25. System.out.println("Duration: " + (time2 - time1) + " ms");

26. }

28. if (verboseMode) {

29. System.out.println("Fibonacci(" + n + ")=" + result);

30. }

32. System.out.println(result);

33. }

35. protected static FibonacciCalculator getCalculator(final char algo) {

36. switch (algo) {

37. // recursif (r)

38. case 'r':

39. return new RecursifFibonnacciCalculator();

41. // memoization (m)

42. case 'm':

43. return new MemoizationFibonnacciCalculator();

45. // terminal (t)

46. case 't':

47. return new TerminalFibonnacciCalculator();

49. // iteratif (i)

50. case 'i':

51. return new IteratifFibonacciCalculator();

53. // direct (d)

54. case 'd':

55. return new DirectFibonacciCalculator();

57. default:

58. System.err.println("Algo inconnu: " + algo);

59. System.exit(1);

60. }

62. return null;

63. }

64. }

Fibo.java

1. package com.icauda.article.commoncli;

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

5. public class Fibo extends AbstractFibo {

7. public static void main(String[] args) {

9. // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)

10. char algo = 'i';

12. // Rang

13. int n = 42;

15. // Timer

16. boolean timerMode = false;

18. // Verbose

19. boolean verboseMode = true;

21. if (verboseMode) {

22. timerMode = true;

23. }

25. // Calculator

26. final FibonacciCalculator calc = getCalculator(algo);

28. // Work

29. work(n, calc, timerMode, verboseMode);

30. }

31. }

FiboManual.java

1. package com.icauda.article.commoncli;

3. import java.util.HashMap;

4. import java.util.Map;

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

8. /*

9. * Usage FiboManual --algo=r --rang=42 --timer=true --verbose=true

10. */

11. public class FiboManual extends AbstractFibo {

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

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

17. // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)

18. char algo = 'i';

19. final String algoFromParamaters = parameters.get("algo");

20. if (algoFromParamaters != null) {

21. algo = algoFromParamaters.charAt(0);

22. }

24. // Rang

25. final String rangFromParamaters = parameters.get("rang");

26. int n = 0;

27. try {

28. n = Integer.valueOf(rangFromParamaters);

29. } catch (Exception e) {

30. System.err.println("Bad parameter: algo");

31. System.exit(3);

32. }

34. // Timer

35. boolean timerMode = false;

36. final String timerFromParamaters = parameters.get("timer");

37. if (timerFromParamaters != null) {

38. timerMode = timerFromParamaters.equalsIgnoreCase("true");

39. }

41. // Verbose

42. boolean verboseMode = true;

43. final String verboseFromParamaters = parameters.get("verbose");

44. if (verboseFromParamaters != null) {

45. verboseMode = verboseFromParamaters.equalsIgnoreCase("true");

46. }

48. if (verboseMode) {

49. timerMode = true;

50. }

52. // Calculator

53. final FibonacciCalculator calc = getCalculator(algo);

55. // Work

56. work(n, calc, timerMode, verboseMode);

57. }

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

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

63. for (final String arg : args) {

64. if (!arg.startsWith("--")) {

65. System.err.println("Bad parameter: " + arg);

66. System.exit(2);

67. }

69. final String[] tab = arg.substring(2).split("=");

70. parameters.put(tab[0], tab[1]);

71. }

73. return parameters;

74. }

75. }

FiboCli.java

1. package com.icauda.article.commoncli;

3. import org.apache.commons.cli.CommandLine;

4. import org.apache.commons.cli.CommandLineParser;

5. import org.apache.commons.cli.DefaultParser;

6. import org.apache.commons.cli.HelpFormatter;

7. import org.apache.commons.cli.Option;

8. import org.apache.commons.cli.Options;

9. import org.apache.commons.cli.ParseException;

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

13. /*

14. * Usage FiboCli --algo r --rang 42 --timer --verbose

15. *               -a       -r        -t      -v

16. */

17. public class FiboCli extends AbstractFibo {

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

21. // Options

22. final Options firstOptions = configFirstParameters();

23. final Options options = configParameters(firstOptions);

25. // On parse l'aide

26. final CommandLineParser parser = new DefaultParser();

27. final CommandLine firstLine = parser.parse(firstOptions, args, true);

29. // Si mode aide

30. boolean helpMode = firstLine.hasOption("help");

31. if (helpMode) {

32. final HelpFormatter formatter = new HelpFormatter();

33. formatter.printHelp("FiboCLI", options, true);

34. System.exit(0);

35. }

37. // On parse la suite

38. final CommandLine line = parser.parse(options, args);

40. // Algo : recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)

41. char algo = line.getOptionValue("algo", "i").charAt(0);

43. // Rang

44. final String rangFromParamaters = line.getOptionValue("rang", "");

45. int n = 0;

46. try {

47. n = Integer.valueOf(rangFromParamaters);

48. } catch (Exception e) {

49. System.err.println("Bad parameter: algo");

50. System.exit(3);

51. }

53. // Timer

54. boolean timerMode = line.hasOption("timer");

56. // Verbose

57. boolean verboseMode = line.hasOption("verbose");

59. if (verboseMode) {

60. timerMode = true;

61. }

63. // Calculator

64. final FibonacciCalculator calc = getCalculator(algo);

66. // Work

67. work(n, calc, timerMode, verboseMode);

68. }

70. private static Options configFirstParameters() {

72. final Option helpFileOption = Option.builder("h") //

73. .longOpt("help") //

74. .desc("Affiche le message d'aide") //

75. .build();

77. final Options firstOptions = new Options();

79. firstOptions.addOption(helpFileOption);

81. return firstOptions;

83. }

85. private static Options configParameters(final Options firstOptions) {

87. final Option algoFileOption = Option.builder("a") //

88. .longOpt("algo") //

89. .desc("Algorithm: recursif (r) / memoization (m) / terminal (t) / iteratif (i) / direct (d)") //

90. .hasArg(true) //

91. .argName("algo") //

92. .required(false) //

93. .build();

95. final Option rangFileOption = Option.builder("r") //

96. .longOpt("rang") //

97. .desc("Rang") //

98. .hasArg(true) //

99. .argName("numeric") //

100. .required(true) //

101. .build();

103. final Option timerFileOption = Option.builder("t") //

104. .longOpt("timer") //

105. .desc("Timer") //

106. .hasArg(false) //

107. .required(false) //

108. .build();

110. final Option verboseFileOption = Option.builder("v") //

111. .longOpt("verbose") //

112. .desc("Verbose") //

113. .hasArg(false) //

114. .required(false) //

115. .build();

117. final Options options = new Options();

119. // First Options

120. for (final Option fo : firstOptions.getOptions()) {

121. options.addOption(fo);

122. }

124. // All other options

125. options.addOption(algoFileOption);

126. options.addOption(rangFileOption);

127. options.addOption(timerFileOption);

128. options.addOption(verboseFileOption);

130. return options;

131. }

132. }