1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
public
interface
FibonacciCalculator {
@param
@return
@throws
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.
public
class
Fibo {
public
static
void
main
(
String[] args) {
char
algo =
'i'
;
int
n =
42
;
boolean
timerMode =
false
;
boolean
verboseMode =
true
;
if
(
verboseMode) {
timerMode =
true
;
FibonacciCalculator calc =
null
;
String algoName =
null
;
switch
(
algo) {
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
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 :
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.
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.
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.
final
Map<
String, String>
parameters =
parseParameters
(
args);
char
algo =
'i'
;
final
String algoFromParamaters =
parameters.get
(
"algo"
);
if
(
algoFromParamaters !=
null
) {
algo =
algoFromParamaters.charAt
(
0
);
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
);
boolean
timerMode =
false
;
final
String timerFromParamaters =
parameters.get
(
"timer"
);
if
(
timerFromParamaters !=
null
) {
timerMode =
timerFromParamaters.equalsIgnoreCase
(
"true"
);
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.
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) {
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.
public
class
FiboManual extends
AbstractFibo {
public
static
void
main
(
final
String[] args) {
final
FibonacciCalculator calc =
getCalculator
(
algo);
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 --verbose
ou en raccourci :
ou même un mélange :
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 » :
1.
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 :
1.
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 :
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.
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.
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.
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);
char
algo =
line.getOptionValue
(
"algo"
, "i"
).charAt
(
0
);
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
);
boolean
timerMode =
line.hasOption
(
"timer"
);
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.
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.
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.
private
static
Options configParameters
(
final
Options firstOptions) {
final
Options options =
new
Options
(
);
for
(
final
Option fo : firstOptions.getOptions
(
)) {
options.addOption
(
fo);
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.
public
class
FiboCli extends
AbstractFibo {
public
static
void
main
(
final
String[] args) throws
ParseException {
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.
final
Options firstOptions =
configFirstParameters
(
);
final
Options options =
configParameters
(
firstOptions);
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.
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 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
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.
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) {
case
'r'
:
return
new
RecursifFibonnacciCalculator
(
);
case
'm'
:
return
new
MemoizationFibonnacciCalculator
(
);
case
't'
:
return
new
TerminalFibonnacciCalculator
(
);
case
'i'
:
return
new
IteratifFibonacciCalculator
(
);
case
'd'
:
return
new
DirectFibonacciCalculator
(
);
default
:
System.err.println
(
"Algo inconnu: "
+
algo);
System.exit
(
1
);
return
null
;
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.
package
com.icauda.article.commoncli;
import
com.icauda.article.commoncli.fibonacci.FibonacciCalculator;
public
class
Fibo extends
AbstractFibo {
public
static
void
main
(
String[] args) {
char
algo =
'i'
;
int
n =
42
;
boolean
timerMode =
false
;
boolean
verboseMode =
true
;
if
(
verboseMode) {
timerMode =
true
;
final
FibonacciCalculator calc =
getCalculator
(
algo);
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.
package
com.icauda.article.commoncli;
import
java.util.HashMap;
import
java.util.Map;
import
com.icauda.article.commoncli.fibonacci.FibonacciCalculator;
public
class
FiboManual extends
AbstractFibo {
public
static
void
main
(
final
String[] args) {
final
Map<
String, String>
parameters =
parseParameters
(
args);
char
algo =
'i'
;
final
String algoFromParamaters =
parameters.get
(
"algo"
);
if
(
algoFromParamaters !=
null
) {
algo =
algoFromParamaters.charAt
(
0
);
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
);
boolean
timerMode =
false
;
final
String timerFromParamaters =
parameters.get
(
"timer"
);
if
(
timerFromParamaters !=
null
) {
timerMode =
timerFromParamaters.equalsIgnoreCase
(
"true"
);
boolean
verboseMode =
true
;
final
String verboseFromParamaters =
parameters.get
(
"verbose"
);
if
(
verboseFromParamaters !=
null
) {
verboseMode =
verboseFromParamaters.equalsIgnoreCase
(
"true"
);
if
(
verboseMode) {
timerMode =
true
;
final
FibonacciCalculator calc =
getCalculator
(
algo);
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;
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.
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;
public
class
FiboCli extends
AbstractFibo {
public
static
void
main
(
final
String[] args) throws
ParseException {
final
Options firstOptions =
configFirstParameters
(
);
final
Options options =
configParameters
(
firstOptions);
final
CommandLineParser parser =
new
DefaultParser
(
);
final
CommandLine firstLine =
parser.parse
(
firstOptions, args, true
);
boolean
helpMode =
firstLine.hasOption
(
"help"
);
if
(
helpMode) {
final
HelpFormatter formatter =
new
HelpFormatter
(
);
formatter.printHelp
(
"FiboCLI"
, options, true
);
System.exit
(
0
);
final
CommandLine line =
parser.parse
(
options, args);
char
algo =
line.getOptionValue
(
"algo"
, "i"
).charAt
(
0
);
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
);
boolean
timerMode =
line.hasOption
(
"timer"
);
boolean
verboseMode =
line.hasOption
(
"verbose"
);
if
(
verboseMode) {
timerMode =
true
;
final
FibonacciCalculator calc =
getCalculator
(
algo);
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
(
);
for
(
final
Option fo : firstOptions.getOptions
(
)) {
options.addOption
(
fo);
options.addOption
(
algoFileOption);
options.addOption
(
rangFileOption);
options.addOption
(
timerFileOption);
options.addOption
(
verboseFileOption);
return
options;