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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
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() :
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.
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 :
Calculating Fibonacci for n: 42
Selected algorithm: Iteratif
Duration: 0 ms
Fibonacci(42)=433494437
433494437III. À la main▲
Durée estimée : 2 minutes.
On voudrait pouvoir lancer le programme et lui passer des arguments comme dans l'exemple suivant :
FiboManual --algo=r --rang=42 --timer=true --verbose=trueIl 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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
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 :
2.
3.
4.
5.
6.
7.
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 :
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.
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 :
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.
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
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 :
FiboCli --algo r --rang 42 --timer --verboseou en raccourci :
FiboCli -a r -r 42 -t -vou même un mélange :
FiboCli --algo -r --rang 42 -t -vVous 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 » :
2.
3.
4.
5.
<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 :
2.
3.
4.
5.
6.
7.
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 :
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.
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 :
2.
3.
4.
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.
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.
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.
2.
3.
4.
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
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 :
2.
3.
4.
5.
6.
7.
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.
2.
3.
4.
5.
6.
7.
// 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 :
2.
3.
4.
5.
6.
7.
// 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 :
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 VerboseLe 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▲
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.
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;
}
}
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.
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);
}
}
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.
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;
}
}
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.
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;
}
}





