Nuiton-utils-commits
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
February 2013
- 4 participants
- 30 discussions
Author: athimel
Date: 2013-02-26 16:30:54 +0100 (Tue, 26 Feb 2013)
New Revision: 2520
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2520
Log:
Fix spelling and conjugation in nuiton-config's index documentation
Modified:
trunk/nuiton-config/src/site/apt/index.apt
Modified: trunk/nuiton-config/src/site/apt/index.apt
===================================================================
--- trunk/nuiton-config/src/site/apt/index.apt 2013-02-26 14:48:17 UTC (rev 2519)
+++ trunk/nuiton-config/src/site/apt/index.apt 2013-02-26 15:30:54 UTC (rev 2520)
@@ -30,23 +30,23 @@
Présentation
- La classe ApplicationConfig a pour but de gérer les options et action
- disponible au sein d'une application. Elle gère aussi bien :
+ La classe ApplicationConfig a pour but de gérer les options et actions
+ disponibles au sein d'une application. Elle gère aussi bien :
- * la lecture de fichier de configuration
+ * la lecture de fichier de configuration ;
- * le parsage de la ligne de commande
+ * le parsage de la ligne de commande ;
- * l'execution des actions
+ * l'execution des actions ;
- * la sauvegarde de la configuration
+ * la sauvegarde de la configuration.
Lecture/écriture
* Lecture des fichiers de configuration
- La lecture des fichiers de configuration est effectuées lors de l'appel
+ La lecture des fichiers de configuration est effectuée lors de l'appel
à la methode <<<parse(String...)>>> en utilisant la valeur de
<<<getConfigFileName()>>> pour trouver les fichiers à lire.
@@ -54,27 +54,27 @@
La sauvegarde des options se fait via une des trois methodes disponibles :
- * <<<save>>> : sauvegarde dans un fichier specifique
+ * <<<save>>> : sauvegarde dans un fichier specifique ;
- * <<<saveForSystem>>> : sauvegarde les donnees dans /etc
+ * <<<saveForSystem>>> : sauvegarde les donnees dans /etc ;
- * <<<saveForUser>>> : sauvegarde les donnees dans $HOME
+ * <<<saveForUser>>> : sauvegarde les donnees dans $HOME.
[]
Seules les options qui ont été modifiées par l'application (par la methode
- <<<setOption()>>> seront sauvegardée. Les variable d'envirronement, les
- arguments de la ligne de commandes(etc...) ne seront pas sauvegardées.
+ <<<setOption()>>>) seront sauvegardées. Les variables d'environnement, les
+ arguments de la ligne de commandes(etc...) ne seront pas sauvegardés.
* Configuration multi instance
- Il est possible d'associé un nom de contexte a une configuration via la
+ Il est possible d'associer un nom de contexte à une configuration via la
methode <<<setAppName("azerty")>>>. Ainsi, les fichiers seront cherchés
- dans le dossier définit par l'option <<<azerty.config.path>>> si elle existe
- (sinon, dans le dossier par defaut) et le nom du fichier cherché defini
+ dans le dossier défini par l'option <<<azerty.config.path>>> si elle existe
+ (sinon, dans le dossier par défaut) et le nom du fichier cherché defini
par l'option <<<azerty.config.file>>>.
- Cett option est utilise par exemple pour installer plusieurs instance
+ Cette option est utilisée par exemple pour installer plusieurs instances
d'application dans un serveur web et que chaque instance aille
chercher ses fichiers de configuration à son propre endroit.
@@ -82,30 +82,29 @@
* Les options de configuration
- L'ordre de prise en compte des options suivant les différentes sources est
- le suivant :
+ L'ordre de prise en compte des options est le suivant :
- * Option renseignées par programmation
+ * Option renseignée par programmation ;
- * Ligne de commandes
+ * Ligne de commande ;
- * Propriétés systèmes (System.getProperties())
+ * Propriétés système (System.getProperties()) ;
- * Propriétés d'envirronement (System.getenv())
+ * Propriétés d'environnement (System.getenv()) ;
- * Fichier du dossier courant ( ./ + nom du fichier)
+ * Fichier du dossier courant ( ./ + nom du fichier) ;
- * Fichier de configuration globale ( /etc/ + nom du fichier)
+ * Fichier de configuration globale ( /etc/ + nom du fichier) ;
- * Fichier dans le classpath ( / + nom du fichier)
+ * Fichier dans le classpath ( / + nom du fichier) ;
- * Valeur par défaut (renseignés à l'init)
+ * Valeur par défaut (renseignée à l'init).
[]
- Cela signifie par exemple que si une option à une valeur par défaut, est renseignée
- dans le fichier /etc et sur la ligne de commande, la valeur presente sur la
- ligne de commande sera prise en compte.
+ Cela signifie par exemple que si une option a une valeur par défaut et qu'elle
+ est renseignée dans le fichier /etc et sur la ligne de commande, c'est la
+ valeur présente sur la ligne de commande qui sera prise en compte.
* Les actions
@@ -117,25 +116,25 @@
Une action est donc définie par le chemin complet de la methode qui traitera
l'action. Si la methode est statique, elle sera appelée directement. Dans le
- cas contraire, la classe contenant la methode sera instancié à partir
- d'un constructeur prenant en parametre seulement la configuration, ou, s'il
- n'est pas disponible, le constructeur par defaut. La methode sera ensuite
- appelée sur cette instance. Les divers instances sont conservés pour effectué
- plusieurs actions.
+ cas contraire, la classe contenant la méthode sera instanciée à partir
+ d'un constructeur prenant en paramètre seulement la configuration, ou, s'il
+ n'est pas disponible, le constructeur par défaut. La méthode sera ensuite
+ appelée sur cette instance. Les diverses instances sont conservées pour
+ effectuer plusieurs actions.
- Les arguments de la methode sont utilisé lors de l'appel. On sont convertit
- dans le bon type. Si la méthode avec des arguments de taille variante (...)
- tous les arguments jusqu'a la prochaine option ou à la fin de la ligne
- seront utilisé.
+ Les arguments de la méthode utilisés lors de l'appel sont convertis
+ dans le bon type. Si la méthode a des arguments de taille variante (...)
+ tous les arguments jusqu'à la prochaine option ou à la fin de la ligne
+ seront utilisés.
- Si vous avez des parametres optionnels, le seul moyen est d'utiliser des
- arguments variant.
+ Si vous avez des paramètres optionnels, le seul moyen est d'utiliser des
+ arguments variants.
- Par exemple, la ligne de commande précédente appelera la methode
+ Par exemple, la ligne de commande précédente appelera la methode :
+-------------------------------------------
public class Test {
- public goLogin(String login, String password, boolean dryRun) {
+ public doLogin(String login, String password, boolean dryRun) {
[...]
}
}
@@ -144,10 +143,10 @@
Les actions ne sont pas executées, mais seulement parsées. Cela signifie
qu'elles seront executées seulement lorsque l'application appelera la méthode
<<<doAction(int)>>>.
- Par defaut, toutes les actions sont de niveau 0 et sont executées dans leur
+ Par défaut, toutes les actions sont de niveau 0 et sont executées dans leur
ordre d'apparition sur la ligne de commande.
- Il est possible de differencier les differentes action en utilisant l'annotation
- <<<@Step>>>
+ Il est possible de différencier les différentes actions en utilisant
+ l'annotation <<<@Step>>>
+-------------------------------------------
doAction(0);
@@ -156,13 +155,13 @@
+-------------------------------------------
Dans cet exemple, les actions 0 et 1 ne sont pas effectuées au même moment.
- C'est très utile par exemple pour executer certaines actions avant le démarrage
- de l'UI par exemple, et d'autre après...
+ C'est très utile par exemple pour éxecuter certaines actions avant le démarrage
+ de l'UI par exemple, et d'autres après...
-* Les arguments non parsées
+* Les arguments non parsés
- La configuration 'consome' les arguments de la ligne de commande qu'elle a
- réussie a traiter. Pour recuperer les autres arguments propres à l'application
+ La configuration 'consomme' les arguments de la ligne de commande qu'elle a
+ réussie à traiter. Pour recupérer les autres arguments propres à l'application
il est possible de les obtenir grace à la méthode <<<getUnparsed()>>>.
Si l'on souhaite forcer la fin du parsing de la ligne de commande il est
possible de mettre <<<-->>>.
@@ -173,7 +172,7 @@
monApplication "mon arg" --option k1 v1 -- --option k2 v2 -- autre
+-------------------------------------------
- Renvera la liste suivante via <<<getUnparsed()>>> :
+ Renverra la liste suivante via <<<getUnparsed()>>> :
+-------------------------------------------
"mon arg", "--option", "k2", "v2", "--", "autre"
@@ -190,7 +189,13 @@
addAlias("-i", "--mon.package.MaClass#MaMethode", "import");
+-------------------------------------------
- Lors du parsing de la ligne de commande, tous les alias sont remplacé par
+ Dans le premier exemple on simplifie une option de flags l'option -v n'attend
+ donc plus d'argument. Dans le second exemple on simplifie une option qui
+ attend encore un argment de type File. Enfin dans le troisieme exemple
+ on simplifie la syntaxe d'une action et on force le premier argument de
+ l'action à être "import".
+
+ Lors du parsing de la ligne de commande, tous les alias sont remplacés par
leur correspondance. Il est donc possible d'utiliser ce mecanisme pour
autre chose :
@@ -198,49 +203,43 @@
addAlias("cl", "Code Lutin");
+-------------------------------------------
- Dans le premier exemple on simplifie une option de flags l'option -v n'attend
- donc plus d'argument. Dans le second exemple on simplifie une option qui
- attend encore un argment de type File. Enfin dans le troisieme exemple
- on simplifie la syntaxe d'une action et on force le premier argument de
- l'action a etre "import".
-
* Conversion de type
- Pour convertir les types des options et arguments de methodes,
+ Pour convertir les types des options et arguments de méthodes,
{{{http://commons.apache.org/beanutils/}commons-beanutils}} est utilisé.
Les types actuellement supporté sont :
- * <<<java.lang.String>>>
+ * <<<java.lang.String>>> ;
- * <<<java.io.File>>>
+ * <<<java.io.File>>> ;
- * <<<java.net.URL>>>
+ * <<<java.net.URL>>> ;
- * <<<java.lang.Class>>>
+ * <<<java.lang.Class>>> ;
- * <<<java.sql.Date>>>
+ * <<<java.sql.Date>>> ;
- * <<<java.sql.Time>>>
+ * <<<java.sql.Time>>> ;
- * <<<java.sql.Timestamp>>>
+ * <<<java.sql.Timestamp>>> ;
* Les tableaux d'un type primitif ou {@link String}. Chaque élément doit
être séparé par une virgule.
[]
- Pour utiliser d'autre type, il suffit de le enregistrer dans beanutils via
- la mézthode <<<ConvertUtils.register(Converter, Class)>>>
+ Pour utiliser d'autres types, il suffit de les enregistrer dans beanutils via
+ la méthode <<<ConvertUtils.register(Converter, Class)>>>
* Les substitutions de variable
- La configuration de variable supporte la substitution par d'autre variable
- via la synthaxe <<<$\{xxx\}>>> où <<<xxx>>> est une autre variable de
- la configuration
+ La configuration de variable supporte la substitution par d'autres variables
+ via la syntaxe <<<$\{xxx\}>>> où <<<xxx>>> est une autre variable de
+ la configuration.
- Par exemple (fichier de configuration):
+ Par exemple (fichier de configuration) :
+-------------------------------------------
application.name = Mon Appli
@@ -249,13 +248,13 @@
+-------------------------------------------
L'appel de l'option <<<application.info>>> via la methode <<<getOption()>>>
- retournera une chaine de la forme:
+ retournera une chaîne de la forme :
+-------------------------------------------
Mon Appli 1.2.3 (1.6.0_18)
+-------------------------------------------
- À noter que les substitutions ne sont remplacée qu'a leur lecture, la sauvegarde
+ À noter que les substitutions ne sont remplacées qu'a leur lecture, la sauvegarde
de l'option <<<application.info>>> se fera sans remplacement.
Mise en oeuvre
@@ -265,13 +264,13 @@
Voici l'ensemble des tâches à effectuer pour définir une configuration
d'application :
- * Creation d'une sous classes d'<<<ApplicationConfig>>>
+ * Creation d'une sous classe d'<<<ApplicationConfig>>> ;
- * Ajout des options par défaut
+ * Ajout des options par défaut ;
- * Creation des classes et méthodes d'actions
+ * Création des classes et méthodes d'actions ;
- * Déclaration des alias des options et actions
+ * Déclaration des alias des options et actions.
[]
@@ -280,33 +279,33 @@
+-------------------------------------------
public class MyConfig extends ApplicationConfig {
- public final static int AFTER_LOGIN = 1;
+ public static final int AFTER_LOGIN = 1;
public MyConfig () {
- // options par defaut
- setDefaultOption("user", "anonymous");
- setDefaultOption("password", "");
- // ajout des alias
- addAlias("-u", "--user");
- addAlias("-p", "--password");
- addActionAlias("--login", MyConfig.class.getName + "#" + doLogin");
+ // options par défaut
+ setDefaultOption("user", "anonymous");
+ setDefaultOption("password", "");
+ // ajout des alias
+ addAlias("-u", "--user");
+ addAlias("-p", "--password");
+ addActionAlias("--login", MyConfig.class.getName + "#" + "doLogin");
}
public void setUser(String user) {
- setOption("user", user);
+ setOption("user", user);
}
public void setUser(String user) {
- setOption("user", user);
+ setOption("user", user);
}
public void doLogin(String user, String password) {
- [...]
+ [...]
}
@Step(AFTER_LOGIN)
public void doSomething() {
- [...]
+ [...]
}
}
+-------------------------------------------
@@ -314,7 +313,7 @@
* Usage
La configuration doit principalement être initilalisée grâce à la méthode
- <<<parse(String[])>>> avant d'être utilisé.
+ <<<parse(String[])>>> avant d'être utilisée.
+-------------------------------------------
public static void main(String[] args) {
@@ -365,11 +364,11 @@
+-------------------------------------------
Puis ajouter le fichier <META-INF/services/org.nuiton.util.ApplicationConfigProvider>
- dans les resources du projet :
+ dans les resources du projet :
+-------------------------------------------
org.chorem.pollen.PollenApplicationConfigProvider
+-------------------------------------------
- Cela permet ensuite par exemple de générer un rapport contenant toutes les
- options disnible dans l'application.
+ Cela permet ensuite, par exemple, de générer un rapport contenant toutes les
+ options disponibles dans l'application.
1
0
Author: athimel
Date: 2013-02-26 15:48:17 +0100 (Tue, 26 Feb 2013)
New Revision: 2519
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2519
Log:
Improve maven-site rendering on nuiton-csv index page
Modified:
trunk/nuiton-csv/src/site/apt/index.apt
Modified: trunk/nuiton-csv/src/site/apt/index.apt
===================================================================
--- trunk/nuiton-csv/src/site/apt/index.apt 2013-02-26 14:46:18 UTC (rev 2518)
+++ trunk/nuiton-csv/src/site/apt/index.apt 2013-02-26 14:48:17 UTC (rev 2519)
@@ -31,34 +31,38 @@
Présentation
- nuiton-csv définit une api simple d'import-export au format csv. Cette api
+ <<nuiton-csv>> définit une api simple d'import-export au format CSV. Cette API
permet de construire un modèle d'import (et/ou d'export) où les différentes
préocupations sont bien séparées.
- Pour un import, et pour chaque ligne à importer, on a trois choses à faire :
+* Import
- - lire la donnée depuis la source d'entrée
+ Pour un import, et pour chaque ligne à importer, il y a trois choses à faire :
- - convertir la donnée en objet
+ * lire la donnée depuis la source d'entrée
- - persister la donnée convertie dans un objet
+ * convertir la donnée en objet
+ * persister la donnée convertie dans un objet
+
La classe <<org.nuiton.util.csv.Import>> permet simplement d'effectuer des
imports, une fois le modèle crée.
- Pour un export et pour chaque objet à persister dans le fichier csv, on a
+* Export
+
+ Pour un export et pour chaque objet à persister dans le fichier csv, il y a
aussi trois choses :
- - lire la donnée depuis l'objet à persister
+ * lire la donnée depuis l'objet à persister
- - convertir la donnée au format texte
+ * convertir la donnée au format texte
- - persister la donnée convertie dans le flux de sortie
+ * persister la donnée convertie dans le flux de sortie
La classe <<org.nuiton.util.csv.Export>> permet simplement d'effectuer un
export, une fois le modèle d'export crée et les données à persister récupérées.
-Api
+API
* org.nuiton.util.csv.ValueFormatter
1
0
26 Feb '13
Author: athimel
Date: 2013-02-26 15:46:18 +0100 (Tue, 26 Feb 2013)
New Revision: 2518
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2518
Log:
Let tests be JDK6 compatible
Modified:
trunk/nuiton-utils/src/test/java/org/nuiton/util/SemVerTest.java
Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/SemVerTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/SemVerTest.java 2013-02-26 14:45:02 UTC (rev 2517)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/SemVerTest.java 2013-02-26 14:46:18 UTC (rev 2518)
@@ -207,7 +207,7 @@
SemVer vj = new SemVer(versions[j]);
int result = normalize(vi.compareTo(vj));
- int expected = Integer.compare(i, j);
+ int expected = Integer.valueOf(i).compareTo(j); // AThimel 2013/02/26 Rewritten for JDK6 compatibility. Was: Integer.compare(i, j);
Assert.assertTrue(String.format(
"Bad compare: Compare(%s, %s) = %s, expected %s",
1
0
26 Feb '13
Author: athimel
Date: 2013-02-26 15:45:02 +0100 (Tue, 26 Feb 2013)
New Revision: 2517
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2517
Log:
[ServiceExporter] Add log in case Registry creation fails
Modified:
trunk/nuiton-utils/src/main/java/org/nuiton/util/rmi/ServiceExporter.java
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/rmi/ServiceExporter.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/rmi/ServiceExporter.java 2013-02-26 08:41:43 UTC (rev 2516)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/rmi/ServiceExporter.java 2013-02-26 14:45:02 UTC (rev 2517)
@@ -81,6 +81,9 @@
try {
result = LocateRegistry.createRegistry(PORT);
} catch (ExportException ee) { // This is the particular case when a registry is already running but not on the correct port.
+ if (log.isWarnEnabled()) {
+ log.warn("Unable to create registry, try using the default one", ee);
+ }
// Try the default port
result = LocateRegistry.getRegistry();
1
0
r2516 - trunk/nuiton-updater/src/main/java/org/nuiton/util/updater
by tchemit@users.nuiton.org 26 Feb '13
by tchemit@users.nuiton.org 26 Feb '13
26 Feb '13
Author: tchemit
Date: 2013-02-26 09:41:43 +0100 (Tue, 26 Feb 2013)
New Revision: 2516
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2516
Log:
refs #2541: Introduce nuiton-updater module (improve some code and use new ApplicationConfig)
Modified:
trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java
Modified: trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java
===================================================================
--- trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java 2013-02-26 08:15:50 UTC (rev 2515)
+++ trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java 2013-02-26 08:41:43 UTC (rev 2516)
@@ -35,8 +35,8 @@
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.VFS;
import org.apache.commons.vfs2.provider.http.HttpFileSystemConfigBuilder;
-import org.nuiton.util.ApplicationConfig;
-import org.nuiton.util.ArgumentsParserException;
+import org.nuiton.util.config.ApplicationConfig;
+import org.nuiton.util.config.ArgumentsParserException;
import org.nuiton.util.VersionUtil;
import java.io.BufferedInputStream;
@@ -129,20 +129,20 @@
*/
public class ApplicationUpdater {
- /** to use log facility, just put in your code: log.info(\"...\"); */
- static private Log log = LogFactory.getLog(ApplicationUpdater.class);
+ /** Logger. */
+ private static final Log log = LogFactory.getLog(ApplicationUpdater.class);
final static private String SEPARATOR_KEY = ".";
- final static public String HTTP_PROXY = "http_proxy";
+ public static final String HTTP_PROXY = "http_proxy";
- final static public String URL_KEY = "url";
+ public static final String URL_KEY = "url";
- final static public String AUTHENTICATION_KEY = "auth";
+ public static final String AUTHENTICATION_KEY = "auth";
- final static public String VERSION_KEY = "version";
+ public static final String VERSION_KEY = "version";
- final static public String VERSION_FILE = "version.appup";
+ public static final String VERSION_FILE = "version.appup";
protected ApplicationConfig config;
@@ -179,8 +179,12 @@
* @param async if true, check is done in background mode
* @param callback callback used to interact with updater, can be null
*/
- public void update(String vfsPropertiesURL, File currentDir, File destDir, boolean async, ApplicationUpdaterCallback callback) {
- Updater up = new Updater(config, vfsPropertiesURL, currentDir, destDir, callback);
+ public void update(String url,
+ File currentDir,
+ File destDir,
+ boolean async,
+ ApplicationUpdaterCallback callback) {
+ Updater up = new Updater(config, url, currentDir, destDir, callback);
if (async) {
Thread thread = new Thread(up, ApplicationUpdater.class.getSimpleName());
thread.start();
@@ -306,7 +310,7 @@
* Par exemple si un fichier se nomme "monApp-1.2/Readme.txt" il se
* nommera au final "monApp/Readme.txt"
*
- * @param proxy le proxy a utiliser pour la connexion a l'url
+ * @param vfsConfig le proxy a utiliser pour la connexion a l'url
* @param info information sur l'application a mettre a jour
* @throws Exception
*/
@@ -345,7 +349,8 @@
* @throws FileSystemException
*/
protected void deepCopy(FileSystemOptions vfsConfig,
- String srcPath, String targetPath) throws FileSystemException {
+ String srcPath,
+ String targetPath) throws FileSystemException {
FileSystemManager fsManager = VFS.getManager();
FileObject archive = fsManager.resolveFile(srcPath, vfsConfig);
1
0
Author: tchemit
Date: 2013-02-26 09:15:50 +0100 (Tue, 26 Feb 2013)
New Revision: 2515
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2515
Log:
refs #2506: Introduce nuiton-config module
Added:
trunk/nuiton-config/
trunk/nuiton-config/LICENSE.txt
trunk/nuiton-config/README.txt
trunk/nuiton-config/changelog.txt
trunk/nuiton-config/pom.xml
trunk/nuiton-config/src/
trunk/nuiton-config/src/license/
trunk/nuiton-config/src/license/THIRD-PARTY.properties
trunk/nuiton-config/src/main/
trunk/nuiton-config/src/main/java/
trunk/nuiton-config/src/main/java/org/
trunk/nuiton-config/src/main/java/org/nuiton/
trunk/nuiton-config/src/main/java/org/nuiton/util/
trunk/nuiton-config/src/main/java/org/nuiton/util/config/
trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfig.java
trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigHelper.java
trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigProvider.java
trunk/nuiton-config/src/main/java/org/nuiton/util/config/ArgumentsParserException.java
trunk/nuiton-config/src/main/resources/
trunk/nuiton-config/src/main/resources/i18n/
trunk/nuiton-config/src/main/resources/i18n/nuiton-config_en_GB.properties
trunk/nuiton-config/src/main/resources/i18n/nuiton-config_es_ES.properties
trunk/nuiton-config/src/main/resources/i18n/nuiton-config_fr_FR.properties
trunk/nuiton-config/src/site/
trunk/nuiton-config/src/site/apt/
trunk/nuiton-config/src/site/apt/index.apt
trunk/nuiton-config/src/site/site_fr.xml
trunk/nuiton-config/src/test/
trunk/nuiton-config/src/test/java/
trunk/nuiton-config/src/test/java/org/
trunk/nuiton-config/src/test/java/org/nuiton/
trunk/nuiton-config/src/test/java/org/nuiton/util/
trunk/nuiton-config/src/test/java/org/nuiton/util/config/
trunk/nuiton-config/src/test/java/org/nuiton/util/config/ApplicationConfigTest.java
trunk/nuiton-config/src/test/resources/
trunk/nuiton-config/src/test/resources/log4j.properties
Modified:
trunk/nuiton-updater/pom.xml
trunk/pom.xml
Property changes on: trunk/nuiton-config
___________________________________________________________________
Added: svn:ignore
+ target
.idea
*.ipr
*.iws
*.iml
.project
.classpath
.settings
Added: trunk/nuiton-config/LICENSE.txt
===================================================================
--- trunk/nuiton-config/LICENSE.txt (rev 0)
+++ trunk/nuiton-config/LICENSE.txt 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,166 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
Property changes on: trunk/nuiton-config/LICENSE.txt
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/README.txt
===================================================================
--- trunk/nuiton-config/README.txt (rev 0)
+++ trunk/nuiton-config/README.txt 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,2 @@
+To deploy new version of pom: mvn deploy
+To install localy: mvn install
Property changes on: trunk/nuiton-config/README.txt
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/changelog.txt
===================================================================
--- trunk/nuiton-config/changelog.txt (rev 0)
+++ trunk/nuiton-config/changelog.txt 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,136 @@
+ver 2.0 xxx 201101xx
+
+ * [FEATURE] Add classes to easily export and reuse services to a RMI registry
+
+ver 1.1.3 xxx 201001xx
+ * Use display-name from web.xml file as server name
+
+ver 1.1.2 desbois 20091223
+ * Add generic war launcher (winstone & jetty based)
+ * Add new uncompress method with exclusion filters
+ * [FEATURE] Force application configuration properties to be written sorted
+ * [FEATURE] Add sed and grep method on FileUtil
+
+ver 1.1.1 chemit 20090903
+
+ * [FEATURE] #39 add a filterVersions method in VersionUtil
+
+-- chemit -- Thu, 03 Sep 2009 18:51:54 +0200
+
+
+ver 1.1.0 20090830
+ * can auto-load converters at runtime via a ServiceLoader mecanism (see org.nuiton.util.ConverterUtil#initConverters() )
+ * migrate to org.nuiton groupId
+
+ver 1.0.6 chemit 20090511
+ * bump versions (lutinproject, maven-license-switcher-plugin)
+ * use doxia-modules-jrst instead of maven-jrst-plugin
+ * improve download section on site
+ * fix generics and javadoc
+ * refactor i18n loading with a direct looding mode (see also i18n:bundle goal)
+
+ver 1.0.5 chatellier xxxxxx ?
+ * Add Tar/bzip2 utility class
+ * Add md5 creation on ZipUtil methods
+ * Change MD5 implementation to http://ostermiller.org/utils/MD5.html one.
+
+ver 1.0.4 chemit 20090311
+ * 20090305 [chemit] - improve FileUtil methods : now can specify the component's invoker (fix some focus bugs in fullscreen mode)
+
+ver 1.0.3 chemit 20090218
+ * 20090218 [chemit] - use lutinproject 3.4
+ * 20090209 [chemit] - add inputStreamToFile method in FileUtil + javadoc on this class
+ - can now exclude some keys when saving configurations (for password, for example)
+ * 20090208 [chemit] add PropertyChangedSupport in ApplicationConfig
+ * 20090203 [chemit] fix StringUtil failed tests since to locale.
+ * 20090126 [chemit] i18n Resource class
+ * 20090121 [chemit] fix bug on Resource when a jar manifest classpath contains some XXX:// jar path
+
+ver 1.0.2 chemit 20090107
+ * 20090105 [chemit] add getCurrentDirectory method in FileUtil
+ * 20090104 [chemit] modify I18n loading to not override sentences with empty value are found and there is already a
+ none empty value loaded
+
+ver 1.0.1 chatellier 20081210
+
+ver 1.0 chemit 20081210
+ * 20081205 [chemit] use lutinproject 3.2
+ * 20081120 [chatellier] Remove deprecated HashMapMultiKey
+ * 20081120 [chatellier] Fix i18n lutinutil properties files
+ * 20081118 [chemit] - use lutinproject 3.1
+ - improve i18n loading : skip urls with no i18n directory
+ - introduce ClassLoaderUtil class
+ * 20081101 [chatellier] Remove deprecated I18n._ and replace by temporary code
+
+ver-0-31 chemit 2008????
+ * always build javadoc
+ * Change group id
+ * utilisation de lutinproject 2.4 et nettoyage du pom
+ * reorganisation du site
+ * <poussin> ArgumentsParser.java marked deprecated
+
+ver-0-30 chemit 20080710
+ * <chemit> passage en maven 2 layout directory
+ * <chemit> utilisation de lutinproject 2.3
+ * <chemit> suppression du code vcs du projet
+ * <poussin> add ApplicationConfig class
+ * <poussin> enhance ObjectUtil
+ * <poussin> HashMapMultiKey marked deprecated
+
+ver-0-26 poussin 2007????
+ * bug in concat(Object [] ...), better array type now work
+ * add unaccent in StringUtil
+
+ver-0-25 poussin 20070425
+ * add StringUtil.toArrayXXX(String ... s) methodes
+ * use generic
+
+ver-0-24 poussin
+ * ArgumentsParser have 1 as repetitionMax by default
+ * ArgumentsParser use jdk 1.5 syntaxe (..., <>)
+
+ver-0-23 poussin 20061004
+ * move i18n in lutinutil
+ * add method Resource.getConfigProperties(String, Properties) to chains
+ properties
+
+ver-0-22 poussin 20060913
+ * use Generics in CategorisedListenerSet
+ * add org.codelutin.log package (LutinLog, ...)
+ * remove org.codelutin.util.Log
+
+ver-0-21 poussin 20060907
+
+ * Add TransformedList
+ * Add FileUtil.getTempFile(String):File
+ * add FileUtil.getFile():File that prompt user
+ * add FileUtil.getDirectory(): String that prompt user
+ * add FileUtil.copyRecursively(File, File, String ... patternFilter)
+ * add ZipUtil class to compress/uncompress zip file
+ * Transparente*Reference accept null object
+
+ver-0-17 thimel 20050610
+
+ * Ajout de BoundedList et BoundedListOutOfBoundsException
+
+ver-0-16 poussin 20050526
+
+ * Ajout de la methode getConfigProperties dans Resource
+
+ver-0-9 poussin 20040728
+
+ * Ajout de methode isJar, isZip, dans Resource
+
+ver-0-3 poussin 20040405
+
+ * utilisation de maven pour la gestion du projet
+ * Ajout de ExceptionUtil
+
+ver-0-2 poussin 20031021
+
+ * ajout du parser d'argument, ArgumentsParser
+ * ajout de StringUtil
+
+ver-0-1
+
+ * premier version contient seulement Resource
Property changes on: trunk/nuiton-config/changelog.txt
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/pom.xml
===================================================================
--- trunk/nuiton-config/pom.xml (rev 0)
+++ trunk/nuiton-config/pom.xml 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #%L
+ Nuiton Utils :: Nuiton Utils
+ %%
+ Copyright (C) 2004 - 2010 CodeLutin, Tony Chemit
+ %%
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Lesser Public License for more details.
+
+ You should have received a copy of the GNU General Lesser Public
+ License along with this program. If not, see
+ <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ #L%
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.nuiton</groupId>
+ <artifactId>nuiton-utils-parent</artifactId>
+ <version>2.6.10-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>nuiton-config</artifactId>
+
+ <name>Nuiton Utils :: Nuiton Config</name>
+ <description>ApplicationConfig api.</description>
+ <inceptionYear>2011</inceptionYear>
+
+ <properties>
+
+ <!-- extra files to include in release -->
+ <redmine.releaseFiles>${redmine.libReleaseFiles}</redmine.releaseFiles>
+
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>nuiton-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.nuiton.i18n</groupId>
+ <artifactId>nuiton-i18n</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+
+ <plugins>
+
+ <!-- plugin i18n -->
+ <plugin>
+ <groupId>org.nuiton.i18n</groupId>
+ <artifactId>i18n-maven-plugin</artifactId>
+ <configuration>
+ <silent>true</silent>
+ <bundles>fr_FR,en_GB,es_ES</bundles>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>parserJava</goal>
+ <goal>gen</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ <profiles>
+ <profile>
+ <id>reporting</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <quiet>true</quiet>
+ <links>
+ <link>http://java.sun.com/javase/6/docs/api/</link>
+ </links>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ </profile>
+
+ <!-- create assemblies at release time -->
+ <profile>
+ <id>assembly-profile</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <defaultGoal>package</defaultGoal>
+ <plugins>
+
+ <!-- launch in a release the assembly automaticly -->
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-assemblies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <attach>false</attach>
+ <descriptorRefs>
+ <descriptorRef>deps</descriptorRef>
+ <descriptorRef>full</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </build>
+ </profile>
+
+ </profiles>
+
+</project>
Property changes on: trunk/nuiton-config/pom.xml
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/license/THIRD-PARTY.properties
===================================================================
--- trunk/nuiton-config/src/license/THIRD-PARTY.properties (rev 0)
+++ trunk/nuiton-config/src/license/THIRD-PARTY.properties 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,19 @@
+# Generated by org.codehaus.mojo.license.AddThirdPartyMojo
+#-------------------------------------------------------------------------------
+# Already used licenses in project :
+# - BSD License
+# - COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+# - Common Public License Version 1.0
+# - Indiana University Extreme! Lab Software License, vesion 1.1.1
+# - Lesser General Public License (LGPL) v 3.0
+# - Lesser General Public License (LPGL)
+# - Lesser General Public License (LPGL) v 2.1
+# - MIT License
+# - New BSD License
+# - The Apache Software License, Version 2.0
+#-------------------------------------------------------------------------------
+# Please fill the missing licenses for dependencies :
+#
+#
+#Tue Feb 26 09:10:58 CET 2013
+commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0
Property changes on: trunk/nuiton-config/src/license/THIRD-PARTY.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfig.java
===================================================================
--- trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfig.java (rev 0)
+++ trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfig.java 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,2793 @@
+package org.nuiton.util.config;
+
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Config
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2011 - 2013 CodeLutin, Tony Chemit
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+
+import org.apache.commons.beanutils.ConstructorUtils;
+import org.apache.commons.collections.EnumerationUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.nuiton.util.FileUtil;
+import org.nuiton.util.ObjectUtil;
+import org.nuiton.util.RecursiveProperties;
+import org.nuiton.util.SortedProperties;
+import org.nuiton.util.StringUtil;
+import org.nuiton.util.Version;
+import org.nuiton.util.converter.ConverterUtil;
+
+import javax.swing.KeyStroke;
+import java.awt.Color;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.Writer;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.net.URL;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import static org.nuiton.i18n.I18n._;
+
+/**
+ * Application configuration.
+ * <p/>
+ * <h3>A finir...</h3>
+ * <ul>
+ * <li>Ajout d'annotations sur les methodes
+ * pour preciser plus de chose pour les options (pattern, min/max, alias,
+ * description, ...)
+ * <li>Trouver un moyen de document les options et actions pour automatiquement
+ * generer l'aide en ligne. Pour eviter de devoir maintenir une methode
+ * dans lequel est ecrit l'aide en plus des options.
+ * <li>Prise en compte du flag {@link #useOnlyAliases}
+ * <li>Vu qu'en java on ne peut pas pointer une methode mais seulement une classe
+ * il y a un bout des actions qui sont des chaines (nom de la methode). Il faudrait
+ * faire un plugin maven qui check que l'action existe bien durant la compilation.
+ * Il est simple de le faire a l'execution mais c trop tard :(
+ * <li>Ajouter de la documentation pour {@link #getOptionAsList(String)}
+ * </ul>
+ * <p/>
+ * <h3>Bonnes pratiques</h3>
+ * <p/>
+ * Vous devez créer une factory pour créer les instances d'{@link ApplicationConfig} qui contiendra par exemple une méthode :
+ * <p/>
+ * <pre>
+ *
+ * public static ApplicationConfig getConfig(
+ * Properties props, String configFilename, String ... args) {
+ *
+ * ApplicationConfig conf = new ApplicationConfig(
+ * MyAppConfigOption.class, MyAppConfigAction.class,
+ * props, configFilename);
+ *
+ * try {
+ * conf.parse(args);
+ * } catch (ArgumentsParserException eee) {
+ * if (log.isErrorEnabled()) {
+ * log.error("Can't load app configuration", eee);
+ * }
+ * }
+ * return conf;
+ * }
+ *
+ * </pre>
+ * <p/>
+ * <ul>
+ * <li>MyAppConfigOption doit étendre {@link OptionDef} et décrir la configuration de l'application.
+ * <li>MyAppConfigAction doit étendre {@link ActionDef} et décrir la liste des options
+ * et de leur alias disponible pour l'application.
+ * </ul>
+ * <p/>
+ * <h3>Lecture des fichiers de configuration</h3>
+ * <p/>
+ * La lecture des fichiers de configuration se fait durant l'appel de la methode
+ * {@link #parse(String...)} en utilisant la valeur de qui doit être définit
+ * dans les options avec pour clef {@link ApplicationConfig#CONFIG_FILE_NAME} pour
+ * trouver les fichiers (voir Les options de configuration pour l'ordre de
+ * chargement des fichiers)
+ * <p/>
+ * <h3>La sauvegarde</h3>
+ * La sauvegarde des options se fait via une des trois methodes disponibles :
+ * <ul>
+ * <li> {@link #save(File, boolean, String...)} sauve les données dans le fichier demandé
+ * <li> {@link #saveForSystem(String...)} sauvegarde les donnees dans /etc
+ * <li> {@link #saveForUser(String...)} sauvegarde les donnees dans $HOME
+ * </ul>
+ * <p/>
+ * Lors de l'utilisation de la methode {@link #saveForSystem(String...)} ou
+ * {@link #saveForUser(String...)} seules les options lues dans un fichier ou modifiées par
+ * programmation ({@link #setOption(String, String)} seront sauvegardées. Par exemple les
+ * options passees sur la ligne de commande ne seront pas sauvees.
+ * <p/>
+ * <h3>Les options de configuration</h3>
+ * <p/>
+ * Cette classe permet de lire les fichiers de configuration, utiliser les
+ * variable d'environnement et de parser la ligne de commande. L'ordre de prise
+ * en compte des informations trouvées est le suivant (le premier le plus
+ * important) :
+ * <ul>
+ * <li>options ajoutees par programmation: {@link #setOption(String, String)}</li>
+ * <li>ligne de commande</li>
+ * <li>variable d'environnement de la JVM: java -Dkey=value</li>
+ * <li>variable d'environnement; export key=value</li>
+ * <li>fichier de configuration du repertoire courant: $user.dir/filename</li>
+ * <li>fichier de configuration du repertoire home de l'utilisateur: $user.home/.filename</li>
+ * <li>fichier de configuration du repertoire /etc: /etc/filename</li>
+ * <li>fichier de configuration trouve dans le classpath: $CLASSPATH/filename</li>
+ * <li>options ajoutees par programmation: {@link #defaults}.put(key, value)</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * Les options sur la ligne de commande sont de la forme:
+ * <pre>
+ * --option key value
+ * --monOption key value1 value2
+ * </pre>
+ * <p/>
+ * <ul>
+ * <li>--option key value: est la syntaxe par defaut
+ * <li>--monOption key value1 value2: est la syntaxe si vous avez ajouter une
+ * methode setMonOption(key, value1, value2) sur votre classe de configuration
+ * qui herite de {@link ApplicationConfig}. Dans ce cas vous pouvez mettre les
+ * arguments que vous souhaitez du moment qu'ils soient convertibles de la
+ * representation String vers le type que vous avez mis.
+ * </ul>
+ * <p/>
+ * <h3>Les actions</h3>
+ * <p/>
+ * Les actions ne peuvent etre que sur la ligne de commande. Elles sont de la
+ * forme:
+ * <pre>
+ * --le.package.LaClass#laMethode arg1 arg2 arg3 ... argN
+ * </pre>
+ * <p/>
+ * Une action est donc defini par le chemin complet vers la methode qui traitera
+ * l'action. Cette methode peut-etre une methode static ou non. Si la methode
+ * n'est pas static lors de l'instanciation de l'objet on essaie de passer en
+ * parametre du constructeur la classe de configuration utilisee pour permettre
+ * a l'action d'avoir a sa disposition les options de configuration. Si aucun
+ * constructeur avec comme seul parametre une classe heritant de
+ * {@link ApplicationConfig} n'existe alors le constructeur par defaut est
+ * utilise (il doit etre accessible). Toutes methodes d'actions faisant
+ * parties d'un meme objet utiliseront la meme instance de cette objet lors
+ * de leur execution.
+ * <p/>
+ * Si la methode utilise les arguments variants alors tous les arguments
+ * jusqu'au prochain -- ou la fin de la ligne de commande sont utilises. Sinon
+ * Le nombre exact d'argument necessaire a la methode sont utilises.
+ * <p/>
+ * Les arguments sont automatiquement converti dans le bon type reclame par la
+ * methode.
+ * <p/>
+ * Si l'on veut des arguments optionnels le seul moyen actuellement est
+ * d'utiliser une methode avec des arguments variants
+ * <p/>
+ * Les actions ne sont pas execute mais seulement parsees. Pour les executer
+ * il faut utiliser la méthode {@link #doAction(int)} qui prend en argument un numero
+ * de 'step' ou {@link #doAllAction()} qui fait les actions dans l'ordre de leur step.
+ * Par defaut toutes les actions sont de niveau 0 et sont executee
+ * dans l'ordre d'apparition sur la ligne de commande. Si l'on souhaite
+ * distinguer les actions il est possible d'utiliser l'annotation
+ * {@link ApplicationConfig.Action.Step} sur la methode qui fera l'action en
+ * precisant une autre valeur que 0.
+ * <pre>
+ * doAction(0);
+ * ... do something ...
+ * doAction(1);
+ * </pre>
+ * dans cette exemple on fait un traitement entre l'execution des actions
+ * de niveau 0 et les actions de niveau 1.
+ * <p/>
+ * <h3>Les arguments non parsées</h3>
+ * Tout ce qui n'est pas option ou action est considere comme non parse et peut
+ * etre recupere par la methode {@link #getUnparsed}. Si l'on souhaite forcer
+ * la fin du parsing de la ligne de commande il est possible de mettre --.
+ * Par exemple:
+ * <pre>
+ * monProg "mon arg" --option k1 v1 -- --option k2 v2 -- autre
+ * </pre>
+ * Dans cet exemple seule la premiere option sera considere comme une option.
+ * On retrouvera dans {@code unparsed}: "mon arg", "--option", "k2", "v2", "--",
+ * "autre"
+ * <p/>
+ * <h3>Les alias</h3>
+ * On voit qu'aussi bien pour les actions que pour les options, le nom de la
+ * methode doit etre utilise. Pour eviter ceci il est possible de definir
+ * des alias ce qui permet de creer des options courtes par exemple. Pour cela,
+ * on utilise la methode {@link #addAlias(String, String...)}.
+ * <pre>
+ * addAlias("-v", "--option", "verbose", "true");
+ * addAlias("-o", "--option", "outputfile");
+ * addAlias("-i", "--mon.package.MaClass#MaMethode", "import");
+ * </pre>
+ * En faite avant le parsing de la ligne de commande tous les alias trouves sont
+ * automatiquement remplacer par leur correspondance. Il est donc possible
+ * d'utiliser ce mecanisme pour autre chose par exemple:
+ * <pre>
+ * addAlias("cl", "Code Lutin");
+ * addAlias("bp", "Benjamin POUSSIN);
+ * </pre>
+ * Dans le premier exemple on simplifie une option de flags l'option -v n'attend
+ * donc plus d'argument. Dans le second exemple on simplifie une option qui
+ * attend encore un argment de type File. Enfin dans le troisieme exemple
+ * on simplifie la syntaxe d'une action et on force le premier argument de
+ * l'action a etre "import".
+ * <p/>
+ * <h3>Conversion de type</h3>
+ * Pour la conversion de type nous utilisons common-beans. Les types supportes
+ * sont:
+ * <ul>
+ * <li> les primitif (byte, short, int, long, float, double, char, boolean)
+ * <li> {@link String}
+ * <li> {@link File}
+ * <li> {@link URL}
+ * <li> {@link Class}
+ * <li> Sql{@link Date}
+ * <li> Sql{@link Time}
+ * <li> Sql{@link Timestamp}
+ * <li> les tableaux d'un type primitif ou {@link String}. Chaque element doit
+ * etre separe par une virgule.
+ * </ul>
+ * <p/>
+ * Pour suporter d'autre type, il vous suffit d'enregistrer de nouveau
+ * converter dans commons-beans.
+ * <p/>
+ * <h3>Les substitutions de variable</h3>
+ * {@link ApplicationConfig} supporte les substition de variables de la forme
+ * <tt>${xxx}</tt> où {@code xxx} est une autre variable de la configuration.
+ * <p/>
+ * Exemple (dans un fichier de configuration):
+ * <pre>
+ * firstname = John
+ * lastname = Doe
+ * fullname = ${firstname} ${lastname}
+ * </pre>
+ * <tt>getOption("fullname")</tt> retournera <tt>"John Doe"</tt>.
+ *
+ * @author Benjamin Poussin <poussin(a)codelutin.com>
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 0.30
+ */
+public class ApplicationConfig {
+
+ /** Logger. */
+ private static final Log log = LogFactory.getLog(ApplicationConfig.class);
+
+ public static final String LIST_SEPARATOR = ",";
+
+ /** Configuration file key option. */
+ public static final String CONFIG_FILE_NAME = "config.file";
+
+ /** Configuration encoding key option. */
+ public static final String CONFIG_ENCODING = "config.encoding";
+
+ /** Permet d'associer un nom de contexte pour prefixer les options {@link #CONFIG_PATH} et {@link #CONFIG_FILE_NAME}. */
+ public static final String APP_NAME = "app.name";
+
+ /**
+ * Property name of {@link #adjusting} internal state.
+ *
+ * @since 1.3
+ */
+ public static final String ADJUSTING_PROPERTY = "adjusting";
+
+ /**
+ * Configuration directory where config path in located.
+ * <p/>
+ * Use default system configuration if nothing is defined:
+ * <ul>
+ * <li>Linux : /etc/xxx.properties
+ * <li>Windows : C:\\Windows\\System32\\xxx.properties
+ * <li>Mac OS : /etc/
+ * </ul>
+ */
+ public static final String CONFIG_PATH = "config.path";
+
+ /** System os name. (windows, linux, max os x) */
+ protected String osName;
+
+ /** TODO */
+ protected boolean useOnlyAliases;
+
+ /** vrai si on est en train de parser les options de la ligne de commande. */
+ protected boolean inParseOptionPhase;
+
+ /** TODO */
+ protected Properties defaults = new Properties();
+
+ /** TODO */
+ protected Properties classpath = new Properties(defaults);
+
+ /** TODO */
+ protected Properties etcfile = new Properties(classpath);
+
+ /** TODO */
+ protected Properties homefile = new Properties(etcfile);
+
+ /** TODO */
+ protected Properties curfile = new Properties(homefile);
+
+ /** TODO */
+ protected Properties env = new Properties(curfile) {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Environnement variables can't contains dot (bash, csh, ...). Dots are
+ * replaced by underscore (_) to find property if property is not find
+ * with dot
+ */
+ @Override
+ public synchronized Object get(Object key) {
+ Object result = super.get(key);
+ if (result == null && key instanceof String) {
+ String skey = (String) key;
+ skey = skey.replace(".", "_");
+ result = super.get(skey);
+ }
+ return result;
+ }
+
+ /**
+ * override to use get(key) and not super.get(key) as in initial implementation :(
+ */
+ @Override
+ public String getProperty(String key) {
+ Object oval = get(key);
+ String sval = (oval instanceof String) ? (String) oval : null;
+ //TODO TC-2013-02-26 Make sure what we want :using Applicationconfig#defaults or super.defaults ?
+ return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
+
+ }
+
+ };
+
+ /** TODO */
+ protected Properties jvm = new Properties(env);
+
+ /** TODO */
+ protected Properties line = new Properties(jvm);
+
+ /** TODO */
+ protected Properties options = new Properties(line);
+
+ /** TODO */
+ protected Map<String, CacheItem<?>> cacheOption = new HashMap<String, CacheItem<?>>();
+
+ /** TODO */
+ protected Map<Class<?>, Object> cacheAction = new HashMap<Class<?>, Object>();
+
+ /** contient apres l'appel de parse, la liste des arguments non utilises */
+ protected List<String> unparsed = new ArrayList<String>();
+
+ /** TODO */
+ protected Map<String, List<String>> aliases = new HashMap<String, List<String>>();
+
+ /** TODO */
+ protected Map<Integer, List<Action>> actions = new HashMap<Integer, List<Action>>();
+
+ /**
+ * Internal state to manage with masse operations on option and control
+ * listeners.
+ * <p/>
+ * for example, if you want to save options, using javaBeans technology,
+ * can add a listener to save each time the property is modified.
+ * <p/>
+ * Says now you have an algorithm to set new values in configuration using
+ * setters but you do NOt want to save each time, add in your saving action
+ * a test to detect if model is adjusting.
+ *
+ * @see #saveUserAction
+ * @since 1.3
+ */
+ private boolean adjusting;
+
+ /** suport of config modification. */
+ protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
+ /** permet de conserver des objets associe avec ce ApplicationConfig */
+ protected Map<String, Object> context = new HashMap<String, Object>();
+
+ /**
+ * Init ApplicationConfig with current simple class name as config file.
+ * <p/>
+ * Also init converters.
+ *
+ * @see ConverterUtil#initConverters()
+ */
+ public ApplicationConfig() {
+ this(null, null);
+ }
+
+ /**
+ * Create configuration for a particular configuration filename
+ *
+ * @param configFilename name of config to use
+ */
+ public ApplicationConfig(String configFilename) {
+ this(null, configFilename);
+ }
+
+ /**
+ * Init ApplicationConfig with current simple class name as config file
+ * and use Properties parameter as defaults
+ * <p/>
+ * Also init converters.
+ *
+ * @param defaults properties
+ * @see ConverterUtil#initConverters()
+ */
+ public ApplicationConfig(Properties defaults) {
+ this(defaults, null);
+ }
+
+ /**
+ * All in one, this constructor allow to pass all necessary argument to
+ * initialise ApplicationConfig and parse command line
+ *
+ * @param defaults properties that override default value of optionClass, can be null
+ * @param configFilename override default config filename, can be null
+ * @since 2.4.8
+ */
+ public ApplicationConfig(Properties defaults, String configFilename) {
+ init(defaults, configFilename);
+ }
+
+ /**
+ * On separt l'init du corps du constructeur, car les sous classes ne doivent
+ * pas l'executer.
+ *
+ * @param defaults properties that override default value of optionClass, can be null
+ * @param configFilename override default config filename, can be null
+ * @since 2.4.9
+ */
+ protected void init(Properties defaults, String configFilename) {
+ if (defaults != null) {
+ // iterate with Properties method and not with Hashtable method to
+ // prevent missed value with chained Properties object
+ for (String key : defaults.stringPropertyNames()) {
+ setDefaultOption(key, defaults.getProperty(key));
+ }
+ }
+
+ setEncoding("UTF-8");
+
+ if (configFilename == null) {
+
+ setConfigFileName(getClass().getSimpleName());
+ } else {
+ setDefaultOption(CONFIG_FILE_NAME, configFilename);
+ }
+
+ // init extra-converters
+ ConverterUtil.initConverters();
+
+ // get system os name
+ osName = System.getProperty("os.name");
+
+ }
+
+ /**
+ * All in one, this constructor allow to pass all necessary argument to
+ * initialise ApplicationConfig and parse command line
+ *
+ * @param optionClass class that describe option, can be null
+ * @param actionClass class that describe action, can be null
+ * @param defaults properties that override default value of optionClass, can be null
+ * @param configFilename override default config filename, can be null
+ * @deprecated since 2.4.8, prefer use {@link #ApplicationConfig(Properties, String)}
+ */
+ @Deprecated
+ public <O extends OptionDef, A extends ActionDef> ApplicationConfig(
+ Class<O> optionClass, Class<A> actionClass,
+ Properties defaults, String configFilename) {
+ this(defaults, configFilename);
+ if (optionClass != null) {
+ loadDefaultOptions(optionClass);
+ }
+ if (actionClass != null) {
+ loadActions(actionClass);
+ }
+ }
+
+ /**
+ * Get user home directory (system property {@code user.home}).
+ *
+ * @return user home directory
+ */
+ public static String getUserHome() {
+ String result = System.getProperty("user.home");
+ return result;
+ }
+
+ /**
+ * Get user name (system property {@code user.name}).
+ *
+ * @return user name
+ */
+ public String getUsername() {
+ String result = getOption("user.name");
+ return result;
+ }
+
+ /**
+ * Get os name (system property {@code os.name}).
+ *
+ * @return os name
+ * @since 2.6.6
+ */
+ public String getOsName() {
+ String result = getOption("os.name");
+ return result;
+ }
+
+ /**
+ * Get os arch (system property {@code os.arch}).
+ *
+ * @return os arch
+ * @since 2.6.6
+ */
+ public String getOsArch() {
+ String result = getOption("os.arch");
+ return result;
+ }
+
+ /**
+ * Load default options of enum pass in param (enum must extend {@link OptionDef})
+ *
+ * @param optionClass to load
+ * @param <O> type of enum extend {@link OptionDef}
+ * @deprecated since 2.4.8, prefer use now {@link #loadDefaultOptions(OptionDef[])}
+ */
+ @Deprecated
+ public <O extends OptionDef> void loadDefaultOptions(Class<O> optionClass) {
+
+ loadDefaultOptions(optionClass.getEnumConstants());
+ }
+
+ /**
+ * Load default given options.
+ *
+ * @param options options to load
+ * @param <O> type of enum extend {@link OptionDef}
+ * @since 2.4.8
+ */
+ public <O extends OptionDef> void loadDefaultOptions(O[] options) {
+
+ // load default option (included configuration file name : important)
+ for (OptionDef o : options) {
+ if (o.getDefaultValue() != null) {
+ setDefaultOption(o.getKey(), o.getDefaultValue());
+ }
+ }
+ }
+
+ /**
+ * Load actions of enum pass in param (enum must extend {@link ActionDef})
+ *
+ * @param actionClass to load
+ * @param <A> type of enum extend {@link ActionDef}
+ * @deprecated since 2.4.8, prefer use now {@link #loadActions(ActionDef[])}
+ */
+ @Deprecated
+ public <A extends ActionDef> void loadActions(Class<A> actionClass) {
+
+ loadActions(actionClass.getEnumConstants());
+ }
+
+ /**
+ * Load given actions.
+ *
+ * @param actions actions to load
+ * @param <A> type of enum extend {@link ActionDef}
+ * @since 2.4.8
+ */
+ public <A extends ActionDef> void loadActions(A[] actions) {
+
+ // load actions
+ for (A a : actions) {
+ for (String alias : a.getAliases()) {
+ addActionAlias(alias, a.getAction());
+ }
+ }
+ }
+
+ /**
+ * Used to put default configuration option in config option. Those options
+ * are used as fallback value.
+ *
+ * @param key default property key
+ * @param value default property value
+ */
+ public void setDefaultOption(String key, String value) {
+ defaults.setProperty(key, value);
+ }
+
+ /**
+ * Save configuration, in specified file.
+ *
+ * @param file file where config will be writen
+ * @param forceAll if true save all config option
+ * (with defaults, classpath, env, command line)
+ * @param excludeKeys optional list of keys to exclude from
+ * @throws IOException if IO pb
+ */
+ public void save(File file,
+ boolean forceAll,
+ String... excludeKeys) throws IOException {
+
+ // store sorted in file
+ Properties prop = new SortedProperties();
+
+ if (forceAll) {
+ prop.putAll(defaults);
+ prop.putAll(classpath);
+ }
+ prop.putAll(etcfile);
+ prop.putAll(homefile);
+ prop.putAll(curfile);
+ if (forceAll) {
+ prop.putAll(jvm);
+ prop.putAll(env);
+ prop.putAll(line);
+ }
+ prop.putAll(options);
+
+ for (String excludeKey : excludeKeys) {
+ prop.remove(excludeKey);
+ }
+
+ // Ano #687 : create parentFile before using it in FileWriter
+ boolean dirCreated =
+ FileUtil.createDirectoryIfNecessary(file.getParentFile());
+ if (dirCreated && log.isDebugEnabled()) {
+ log.debug("Creation of config directory " + file.getParent());
+ }
+ saveResource(file, prop, "Last saved " + new Date());
+ }
+
+ /**
+ * Save configuration, in system directory (/etc/) using the
+ * {@link #getConfigFileName}. Default, env and commande line note saved.
+ *
+ * @param excludeKeys optional list of keys to exclude from
+ */
+ public void saveForSystem(String... excludeKeys) {
+ File file = getSystemConfigFile();
+ if (log.isDebugEnabled()) {
+ log.debug("will save system configuration in " + file);
+ }
+ try {
+ save(file, false, excludeKeys);
+ } catch (IOException eee) {
+ if (log.isWarnEnabled()) {
+ log.warn(_("nuitonutil.error.applicationconfig.save", file),
+ eee);
+ }
+ }
+ }
+
+ /**
+ * Save configuration, in user home directory using the
+ * {@link #getConfigFileName}. Default, env and commande line note saved
+ *
+ * @param excludeKeys optional list of keys to exclude from
+ */
+ public void saveForUser(String... excludeKeys) {
+ File file = getUserConfigFile();
+ if (log.isDebugEnabled()) {
+ log.debug("will save user configuration in " + file);
+ }
+ try {
+ save(file, false, excludeKeys);
+ } catch (IOException eee) {
+ if (log.isWarnEnabled()) {
+ log.warn(_("nuitonutil.error.applicationconfig.save", file),
+ eee);
+ }
+ }
+ }
+
+ /**
+ * Clean the user configuration file (The one in user home) and save it
+ * in user config file.
+ * <p/>
+ * All options with an empty value will be removed from this file.
+ * <p/>
+ * Moreover, like {@link #saveForUser(String...)} the given
+ * {@code excludeKeys} will never be saved.
+ * <p/>
+ * This method can be useful when migrating some configuration from a
+ * version to another one with deprecated options (otherwise they will stay
+ * for ever in the configuration file with an empty value which is not
+ * acceptable).
+ * <p/>
+ * <strong>Important note:</strong> Using this method can have some strange
+ * side effects, since it could then allow to reuse default configurations
+ * from other level (default, env, jvm,...). Use with care only!
+ *
+ * @param excludeKeys optional list of key to not treat in cleaning process,
+ * nor save in user user config file.
+ * @since 2.6.6
+ */
+ public void cleanUserConfig(String... excludeKeys) {
+
+ Set<String> keys = new HashSet<String>(homefile.stringPropertyNames());
+
+ List<String> toExclude = Arrays.asList(excludeKeys);
+
+ for (String key : keys) {
+ if (!toExclude.contains(key)) {
+ String property = homefile.getProperty(key);
+ if (StringUtils.isBlank(property)) {
+ if (log.isInfoEnabled()) {
+ log.info("Remove blank property: " + key);
+ }
+ homefile.remove(key);
+ }
+ }
+ }
+
+ // can now save cleaned user config
+ saveForUser(excludeKeys);
+ }
+
+ /**
+ * Obtain the system config file location.
+ *
+ * @return the system config file location
+ */
+ public File getSystemConfigFile() {
+ File file = new File(getConfigPath(), getConfigFileName());
+ return file;
+ }
+
+ /**
+ * Obtain the user config file location.
+ *
+ * @return the user config file location
+ */
+ public File getUserConfigFile() {
+ return new File(getUserConfigDirectory(), getConfigFileName());
+ }
+
+ /**
+ * Return list of unparsed command line argument
+ *
+ * @return list of unparsed arguments
+ */
+ public List<String> getUnparsed() {
+ return unparsed;
+ }
+
+ /**
+ * Add action to list of action to do.
+ *
+ * @param action action to add, can be null.
+ */
+ public void addAction(Action action) {
+ if (action != null) {
+ Integer step = action.step;
+ List<Action> list = actions.get(step);
+ if (list == null) {
+ list = new LinkedList<Action>();
+ actions.put(step, list);
+ }
+ list.add(action);
+ }
+ }
+
+ /**
+ * Return ordered action step number.
+ * example: 0,1,5,6
+ *
+ * @return ordered action step number
+ * @since 2.4
+ */
+ public List<Integer> getActionStep() {
+ List<Integer> result = new ArrayList<Integer>(actions.keySet());
+ Collections.sort(result);
+ return result;
+ }
+
+ /**
+ * Do all action in specified order step (first 0).
+ *
+ * @throws IllegalAccessException if action invocation failed
+ * @throws IllegalArgumentException if action invocation failed
+ * @throws InvocationTargetException if action invocation failed
+ * @throws InstantiationException if action invocation failed
+ * @see Action.Step
+ * @since 2.4
+ */
+ public void doAllAction() throws IllegalAccessException,
+ IllegalArgumentException,
+ InvocationTargetException,
+ InstantiationException {
+ for (int step : getActionStep()) {
+ doAction(step);
+ }
+ }
+
+ /**
+ * Do action in specified step.
+ *
+ * @param step do action only defined in this step
+ * @throws IllegalAccessException if action invocation failed
+ * @throws IllegalArgumentException if action invocation failed
+ * @throws InvocationTargetException if action invocation failed
+ * @throws InstantiationException if action invocation failed
+ * @see Action.Step
+ */
+ public void doAction(int step) throws IllegalAccessException,
+ IllegalArgumentException,
+ InvocationTargetException,
+ InstantiationException {
+ List<Action> list = actions.get(step);
+ if (list != null) {
+ for (Action a : list) {
+ a.doAction();
+ }
+ }
+ }
+
+ public void setUseOnlyAliases(boolean useOnlyAliases) {
+ this.useOnlyAliases = useOnlyAliases;
+ }
+
+ public boolean isUseOnlyAliases() {
+ return useOnlyAliases;
+ }
+
+ /**
+ * Get the encoding used to read/write resources.
+ * <p/>
+ * This value is stored as an option using the
+ * {@link #getEncodingOption()} key.
+ *
+ * @return the encoding used to read/write resources.
+ * @since 2.3
+ */
+ public String getEncoding() {
+ return getOption(getEncodingOption());
+ }
+
+ /**
+ * Set the new encoding option.
+ *
+ * @param encoding the new value of the option encoding
+ * @since 2.3
+ */
+ public void setEncoding(String encoding) {
+ setDefaultOption(getEncodingOption(), encoding);
+ }
+
+ /**
+ * All argument in aliases as key is substitued by target.
+ *
+ * @param alias alias string as '-v'
+ * @param target substitution as '--option verbose true'
+ */
+ public void addAlias(String alias, String... target) {
+ aliases.put(alias, Arrays.asList(target));
+ }
+
+ /**
+ * Add alias for action. This method put just -- front the actionMethod and
+ * call {@link #addAlias(String, String...)}.
+ *
+ * @param alias the alias to add for the given method action
+ * @param actionMethod must be fully qualified method path:
+ * package.Class#method
+ */
+ public void addActionAlias(String alias, String actionMethod) {
+ addAlias(alias, "--" + actionMethod);
+ }
+
+ /**
+ * Set name of file where options are read (in /etc, $HOME, $CURDIR)
+ * This set used {@link #setDefaultOption(String, String)}.
+ *
+ * @param name file name
+ */
+ public void setConfigFileName(String name) {
+ // put in defaults, this permit user to overwrite it on commande line
+ setDefaultOption(getConfigFileNameOption(), name);
+ }
+
+ /**
+ * Get name of file where options are read (in /etc, $HOME, $CURDIR).
+ *
+ * @return name of file
+ */
+ public String getConfigFileName() {
+ String result = getOption(getConfigFileNameOption());
+ return result;
+ }
+
+ public boolean isAdjusting() {
+ return adjusting;
+ }
+
+ public void setAdjusting(boolean adjusting) {
+ boolean oldvalue = this.adjusting;
+ this.adjusting = adjusting;
+ firePropertyChange(ADJUSTING_PROPERTY, oldvalue, adjusting);
+ }
+
+ protected String getConfigFileNameOption() {
+ String optionName = CONFIG_FILE_NAME;
+ if (getOption(APP_NAME) != null) {
+ optionName = getOption(APP_NAME) + "." + optionName;
+ }
+ return optionName;
+ }
+
+ /**
+ * Obtains the key used to store the option encoding.
+ *
+ * @return the encoding option'key
+ * @since 2.3
+ */
+ protected String getEncodingOption() {
+ String optionName = CONFIG_ENCODING;
+ if (getOption(APP_NAME) != null) {
+ optionName = getOption(APP_NAME) + "." + optionName;
+ }
+ return optionName;
+ }
+
+ /**
+ * Use appName to add a context in config.file and config.path options.
+ * <p/>
+ * Ex for an application named 'pollen' : {@code config.file} option becomes
+ * {@code pollen.config.file} and {@code config.path} becomes
+ * {@code pollen.config.path}
+ *
+ * @param appName to use as application context
+ * @since 1.2.1
+ */
+ public void setAppName(String appName) {
+ setDefaultOption(APP_NAME, appName);
+ }
+
+ /**
+ * Get configuration file path to use.
+ * <p/>
+ * Use (in order) one of the following definition:
+ * <ul>
+ * <li>{@link #CONFIG_PATH} option
+ * <li>system dependant path
+ * </ul>
+ *
+ * @return path to use with endind {@link File#separator}
+ * @since 1.2.1
+ */
+ public String getConfigPath() {
+ // Concat appName to configPath option to specify context for
+ // application deployment
+ String appName = getOption(APP_NAME) != null ?
+ getOption(APP_NAME) + "." : "";
+
+ String result = getOption(appName + CONFIG_PATH);
+
+ if (result == null) {
+ result = getSystemConfigurationPath();
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Configuration path used : " + result);
+ }
+ return result;
+ }
+
+ /**
+ * Get system configuration path.
+ * <p/>
+ * Currently supported:
+ * <ul>
+ * <li>Windows : C:\Windows\System32
+ * <li>Unix : /etc/
+ * </ul>
+ *
+ * @return the system path
+ * @since 1.2.1
+ */
+ protected String getSystemConfigurationPath() {
+
+ String systemPath = null;
+
+ // Windows
+ if (osName.toLowerCase().contains("windows")) {
+
+ // try 1 : %SystemDirectory%
+ try {
+ String systemDirectory = System.getenv("SystemDirectory");
+ if (systemDirectory != null && systemDirectory.length() > 0) {
+ systemPath = systemDirectory;
+ }
+ } catch (SecurityException eee) {
+ if (log.isErrorEnabled()) {
+ log.error("Can't read env property", eee);
+ }
+ }
+
+ // try 2 : %SystemRoot%
+ if (systemPath != null) {
+ try {
+ String systemRoot = System.getenv("SystemRoot");
+ if (systemRoot != null && systemRoot.length() > 0) {
+ systemPath = systemRoot + "\\System32";
+ }
+ } catch (SecurityException eee) {
+ if (log.isErrorEnabled()) {
+ log.error("Can't read env property", eee);
+ }
+ }
+ } else {
+ // default value
+ systemPath = "C:\\Windows\\System32";
+ }
+
+ // %SystemDrive% exists too : C:
+ } else {
+ // All others are unix like
+ // look for in /etc/
+ systemPath = File.separator + "etc" + File.separator;
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(systemPath);
+ }
+ return systemPath;
+ }
+
+ /**
+ * Get user configuration path.
+ * <p/>
+ * Currently supported:
+ * <ul>
+ * <li>Windows : ${user.home}\\Application Data\\
+ * <li>Max os x : ${user.home}/Library/Application Support
+ * <li>Unix : ${user.home}/.config
+ * </ul>
+ * <p/>
+ * Unix norm is based on freedesktop concept explained here :
+ * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ *
+ * @return the user configuration path
+ * @since 1.2.1
+ */
+ public String getUserConfigDirectory() {
+
+ String userPath = null;
+
+ String userHome = null;
+ try {
+ userHome = getUserHome();
+ } catch (SecurityException ignore) {
+ }
+
+ if (userHome != null) {
+ // windows
+ if (osName.toLowerCase().contains("windows")) {
+ try {
+ String appDataEV = System.getenv("APPDATA");
+ if (appDataEV != null && appDataEV.length() > 0) {
+ userPath = appDataEV;
+ }
+ } catch (SecurityException ignore) {
+ }
+
+ if (userPath == null || userPath.isEmpty()) {
+ // ${userHome}\Application Data\
+ userPath = userHome + File.separator + "Application Data";
+ }
+ } else if (osName.toLowerCase().contains("mac os x")) {
+ // ${userHome}/Library/Application Support/${applicationId}
+ userPath = userHome + File.separator +
+ "/Library/Application Support";
+ } else {
+ // ${userHome}/.config/
+ userPath = userHome + "/.config";
+ }
+ }
+
+ // what if null ?
+
+ return userPath;
+ }
+
+ /**
+ * Teste si un option existe ou non.
+ *
+ * @param key la clef de l'option à tester
+ * @return {@code true} si l'option existe, {@code false} sinon.
+ */
+ public boolean hasOption(String key) {
+ // on est oblige de faire un get, car le containsKey n'est pas recursif
+ // sur tous les properties
+ boolean result = options.getProperty(key) != null;
+ return result;
+ }
+
+ /**
+ * Teste si un option existe ou non
+ *
+ * @param key la clef de l'option à tester
+ * @return {@code true} si 'loption existe, {@code false} sinon.
+ */
+ public boolean hasOption(OptionDef key) {
+ boolean result = hasOption(key.getKey());
+ return result;
+ }
+
+ /**
+ * ajoute un objet dans le context, la classe de l'objet est utilise comme cle
+ *
+ * @since 2.4.2
+ */
+ public void putObject(Object o) {
+ putObject(o.getClass().getName(), o);
+ }
+
+ /**
+ * ajoute un objet dans le context, 'name' est utilise comme cle
+ *
+ * @since 2.4.2
+ */
+ public void putObject(String name, Object o) {
+ context.put(name, o);
+ }
+
+ /**
+ * recupere un objet de la class<E>, s'il n'existe pas encore, il est cree
+ * (il faut donc que class<E> soit instanciable
+ * <p/>
+ * E peut prendre en argument du contruteur un objet de type ApplicationConfig
+ *
+ * @since 2.4.2
+ */
+ public <E> E getObject(Class<E> clazz) {
+ E result = getObject(clazz, clazz.getName());
+ return result;
+ }
+
+ /**
+ * recupere un objet ayant le nom 'name', s'il n'existe pas encore, il est
+ * cree en utilisant la class<E>, sinon il est simplement caster vers cette
+ * classe.
+ * <p/>
+ * E peut prendre en argument du contruteur un objet de type ApplicationConfig
+ *
+ * @since 2.4.2
+ */
+ public <E> E getObject(Class<E> clazz, String name) {
+ E result = clazz.cast(context.get(name));
+ if (result == null) {
+ result = ObjectUtil.newInstance(
+ clazz, Collections.singleton(this), true);
+ putObject(name, result);
+ }
+ return result;
+ }
+
+ /**
+ * retourne une nouvelle instance d'un objet dont on recupere la la class
+ * dans la configuration via la cle 'key'. Retourne null si la cle n'est pas
+ * retrouve
+ *
+ * @since 2.4.2
+ */
+ public Object getOptionAsObject(String key) {
+ Object result = null;
+ if (hasOption(key)) {
+ Class<?> clazz = getOptionAsClass(key);
+ result = ObjectUtil.newInstance(
+ clazz, Collections.singleton(this), true);
+ }
+ return result;
+ }
+
+ /**
+ * retourne une nouvelle instance d'un objet dont on recupere la la class
+ * dans la configuration via la cle 'key' et le cast en E. Retourne null
+ * si la cle n'est pas retrouve
+ * <p/>
+ * E peut prendre en argument du contruteur un objet de type ApplicationConfig
+ *
+ * @since 2.4.2
+ */
+ public <E> E getOptionAsObject(Class<E> clazz, String key) {
+ E result = clazz.cast(getOptionAsObject(key));
+ return result;
+ }
+
+ /**
+ * retourne l'objet instancier via la classe recupere dans la configuration
+ * via la cle 'key'. Une fois instancie, le meme objet est toujours retourne.
+ * On null si key n'est pas retrouve.
+ * <p/>
+ * La classe peut avoir un constructeur prenant un ApplicationConfig
+ *
+ * @since 2.4.2
+ */
+ public Object getOptionAsSingleton(String key) {
+ Object result = context.get(key);
+ if (result == null) {
+ result = getOptionAsObject(key);
+ putObject(key, result);
+ }
+ return result;
+ }
+
+ /**
+ * retourne l'objet caster en 'E', instancier via la classe recupere dans la
+ * configuration via la cle 'key'. Une fois instancie, le meme objet est
+ * toujours retourne. On null si key n'est pas retrouve
+ * <p/>
+ * La classe peut avoir un constructeur prenant un ApplicationConfig
+ *
+ * @since 2.4.2
+ */
+ public <E> E getOptionAsSingleton(Class<E> clazz, String key) {
+ E result = clazz.cast(getOptionAsSingleton(key));
+ return result;
+ }
+
+ /**
+ * Set option value.
+ *
+ * @param key property key
+ * @param value property value
+ */
+ public void setOption(String key, String value) {
+ if (inParseOptionPhase) {
+ line.setProperty(key, value);
+ } else {
+ options.setProperty(key, value);
+ }
+ }
+
+ /**
+ * get option value as string.
+ * <p/>
+ * Replace inner ${xxx} value.
+ *
+ * @param key the option's key
+ * @return String representation value
+ */
+ public String getOption(String key) {
+ String value = options.getProperty(key);
+ // replace ${xxx}
+ value = replaceRecursiveOptions(value);
+ return value;
+ }
+
+ /**
+ * Replace included ${xxx} suboptions by their values.
+ *
+ * @param option option to replace into
+ * @return replaced option
+ * @since 1.1.3
+ */
+ protected String replaceRecursiveOptions(String option) {
+
+ // TODO do a common code with RecursiveProperties code
+ // TODO but can't overwrite getProperty() method
+
+ String result = option;
+
+ if (result == null) {
+ return null;
+ }
+
+ //Ex : result="My name is ${myName}."
+ int pos = result.indexOf("${", 0);
+ //Ex : pos=11
+ while (pos != -1) {
+ int posEnd = result.indexOf("}", pos + 1);
+ //Ex : posEnd=19
+ if (posEnd != -1) {
+ String value = getOption(result.substring(pos + 2, posEnd));
+ // Ex : getProperty("myName");
+ if (value != null) {
+ // Ex : value="Thimel"
+ result = result.substring(0, pos) + value +
+ result.substring(posEnd + 1);
+ // Ex : result="My name is " + "Thimel" + "."
+ pos = result.indexOf("${", pos + value.length());
+ // Ex : pos=-1
+ } else {
+ // Ex : value=null
+ pos = result.indexOf("${", posEnd + 1);
+ // Ex : pos=-1
+ }
+ // Ex : pos=-1
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a sub config that encapsulate this ApplicationConfig.
+ *
+ * @param prefix prefix to put automaticaly at beginning of all key
+ * @return sub config that encapsulate this ApplicationConfig
+ * @since 2.4.9
+ */
+ public SubApplicationConfig getSubConfig(String prefix) {
+ SubApplicationConfig result = new SubApplicationConfig(this, prefix);
+ return result;
+ }
+
+ /**
+ * Permet de recuperer l'ensemble des options commencant par une certaine
+ * chaine.
+ *
+ * @param prefix debut de cle a recuperer
+ * @return la liste des options filtrées
+ */
+ public Properties getOptionStartsWith(String prefix) {
+ Properties result = new Properties();
+
+ for (String key : options.stringPropertyNames()) {
+ if (key.startsWith(prefix)) {
+ result.setProperty(key, options.getProperty(key));
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Get option value from a option definition.
+ *
+ * @param key the definition of the option
+ * @return the value for the given option
+ */
+ public Object getOption(OptionDef key) {
+ Object result = getOption(key.getType(), key.getKey());
+ return result;
+ }
+
+ /**
+ * Get option value as typed value.
+ *
+ * @param <T> type of the object wanted as return type
+ * @param clazz type of object wanted as return type
+ * @param key the option's key
+ * @return typed value
+ */
+ public <T> T getOption(Class<T> clazz, String key) {
+ String value = getOption(key);
+ T result = null;
+ if (value != null) {
+ result = (T) convertOption(clazz, key, value, false);
+ }
+
+ return result;
+ }
+
+ /**
+ * Convert value in instance of clazz or List if asList is true
+ * <p/>
+ * example:
+ * <li> convertOption(Boolean.class, "toto", "true,true", false) => false
+ * <li> convertOption(Boolean.class, "toto", null, false) => ? ConverterUtil dependant
+ * <li> convertOption(Boolean.class, "toto", "true,true", true) => [true, true]
+ * <li> convertOption(Boolean.class, "toto", null, true) => []
+ *
+ * @param clazz result type expected
+ * @param key option key
+ * @param value value to convert
+ * @param asList value is string that represente a list
+ * @return the converted option in the required type
+ */
+ protected <T> Object convertOption(Class<T> clazz,
+ String key,
+ String value,
+ boolean asList) {
+ String cacheKey = key + "-" + asList + "-" + clazz.getName();
+
+ int hash = 0;
+ if (value != null) {
+ hash = value.hashCode();
+ }
+
+ CacheItem<?> cacheItem = cacheOption.get(cacheKey);
+ // compute value if value don't exist in cacheOption or
+ // if it's modified since last computation
+ if (cacheItem == null || cacheItem.hash != hash) {
+ if (asList) {
+ List<T> list = new ArrayList<T>();
+ if (value != null) {
+ String[] values = StringUtil.split(value, LIST_SEPARATOR);
+ for (String valueString : values) {
+ // prefer use our convertert method (auto-register more converters)
+ T v = ConverterUtil.convert(clazz, valueString);
+ list.add(v);
+ }
+ }
+ cacheItem = new CacheItem<List<T>>(list, hash);
+ } else {
+ // prefer use our converter method (auto-register more converters)
+ T v = ConverterUtil.convert(clazz, value);
+ cacheItem = new CacheItem<T>(v, hash);
+ }
+ // add new item to the cache
+ cacheOption.put(cacheKey, cacheItem);
+ }
+
+ // take result in item
+ Object result = cacheItem.item;
+
+ return result;
+ }
+
+ /**
+ * Help to convert value to list of object. If no option for this key
+ * empty List is returned finaly
+ *
+ * @param key the key of searched option
+ * @return value of option list
+ */
+ public OptionList getOptionAsList(String key) {
+ String value = getOption(key);
+ OptionList result = new OptionList(this, key, value);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link File}.
+ *
+ * @param key the option's key
+ * @return value as file
+ */
+ public File getOptionAsFile(String key) {
+ File result = getOption(File.class, key);
+ if (result != null) {
+ result = result.getAbsoluteFile();
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Color}.
+ *
+ * @param key the option's key
+ * @return value as color
+ */
+ public Color getOptionAsColor(String key) {
+ Color color = getOption(Color.class, key);
+ return color;
+ }
+
+ /**
+ * Get option value as {@link Properties}, this property must be a filepath
+ * and file must be a properties.
+ * <p/>
+ * Returned Properties is {@link RecursiveProperties}.
+ *
+ * @param key the option's key
+ * @return Properties object loaded with value pointed by file
+ * @throws IOException if exception occured on read file
+ */
+ public Properties getOptionAsProperties(String key) throws IOException {
+ File file = getOptionAsFile(key);
+ Properties prop = new RecursiveProperties();
+ FileReader reader = new FileReader(file);
+ try {
+ prop.load(reader);
+ } finally {
+ reader.close();
+ }
+ return prop;
+ }
+
+ /**
+ * Get option value as {@link URL}.
+ *
+ * @param key the option's key
+ * @return value as URL
+ */
+ public URL getOptionAsURL(String key) {
+ URL result = getOption(URL.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Class}.
+ *
+ * @param key the option's key
+ * @return value as Class
+ */
+ public Class<?> getOptionAsClass(String key) {
+ Class<?> result = getOption(Class.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Date}.
+ *
+ * @param key the option's key
+ * @return value as Date
+ */
+ public Date getOptionAsDate(String key) {
+ Date result = getOption(Date.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Time}.
+ *
+ * @param key the option's key
+ * @return value as Time
+ */
+ public Time getOptionAsTime(String key) {
+ Time result = getOption(Time.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Timestamp}.
+ *
+ * @param key the option's key
+ * @return value as Timestamp
+ */
+ public Timestamp getOptionAsTimestamp(String key) {
+ Timestamp result = getOption(Timestamp.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@code int}.
+ *
+ * @param key the option's key
+ * @return value as {@code int}
+ */
+ public int getOptionAsInt(String key) {
+ Integer result = getOption(Integer.class, key);
+ if (result == null) {
+ // primitive value can not be null
+ result = 0;
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@code long}.
+ *
+ * @param key the option's key
+ * @return value as {@code long}
+ */
+ public long getOptionAsLong(String key) {
+ Long result = getOption(Long.class, key);
+ if (result == null) {
+ // primitive value can not be null
+ result = 0L;
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@code float}.
+ *
+ * @param key the option's key
+ * @return value as {@code float}
+ * @since 2.2
+ */
+ public float getOptionAsFloat(String key) {
+ Float result = getOption(Float.class, key);
+ if (result == null) {
+ // primitive value can not be null
+ result = 0f;
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@code double}.
+ *
+ * @param key the option's key
+ * @return value as {@code double}
+ */
+ public double getOptionAsDouble(String key) {
+ Double result = getOption(Double.class, key);
+ if (result == null) {
+ // primitive value can not be null
+ result = 0d;
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@code boolean}.
+ *
+ * @param key the option's key
+ * @return value as {@code boolean}.
+ */
+ public boolean getOptionAsBoolean(String key) {
+ Boolean result = getOption(Boolean.class, key);
+ if (result == null) {
+ // primitive value can not be null
+ result = false;
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Locale}.
+ *
+ * @param key the option's key
+ * @return value as {@link Locale}.
+ * @since 2.0
+ */
+ public Locale getOptionAsLocale(String key) {
+ Locale result = getOption(Locale.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Version}.
+ *
+ * @param key the option's key
+ * @return value as {@link Version}.
+ * @since 2.0
+ */
+ public Version getOptionAsVersion(String key) {
+ Version result = getOption(Version.class, key);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link KeyStroke}.
+ *
+ * @param key the option's key
+ * @return value as {@link KeyStroke}.
+ * @since 2.5.1
+ */
+ public KeyStroke getOptionAsKeyStroke(String key) {
+ KeyStroke result = getOption(KeyStroke.class, key);
+ return result;
+ }
+
+
+ /**
+ * Get all options from configuration.
+ *
+ * @return Properties which contains all options
+ */
+ public Properties getOptions() {
+ return options;
+ }
+
+ /**
+ * Set manually options when you don't want to use parse method to check
+ * properties file configured by {@link #setConfigFileName(String)}.
+ *
+ * @param options Properties which contains all options to set
+ */
+ public void setOptions(Properties options) {
+ this.options = options;
+ }
+
+ /**
+ * Get all options as flat {@link Properties} object (replace inner options).
+ *
+ * @return flat Properties object
+ * @since 1.2.2
+ */
+ public Properties getFlatOptions() {
+ return getFlatOptions(true);
+ }
+
+ /**
+ * Get all options as flat {@link Properties} object.
+ *
+ * @param replaceInner if {@code true} replace imbricated options by theirs values
+ * @return flat Properties object
+ * @since 1.2.2
+ */
+ public Properties getFlatOptions(boolean replaceInner) {
+ Properties props = new Properties();
+ for (String propertyKey : options.stringPropertyNames()) {
+ String propertyValue;
+ if (replaceInner) {
+ // replace ${xxx} option
+ propertyValue = getOption(propertyKey);
+ } else {
+ // do not replace ${xxx} option
+ propertyValue = options.getProperty(propertyKey);
+ }
+ props.setProperty(propertyKey, propertyValue);
+ }
+ return props;
+ }
+
+ /**
+ * Install the {@link #saveUserAction} on givne {@code properties}.
+ *
+ * @param properties properties on which insalls the saveUserAction
+ */
+ protected void installSaveUserAction(String... properties) {
+
+ // pass in adjusting state
+ setAdjusting(true);
+
+ try {
+ // ajout de tous les listeners pour sauver la configuration
+ // lors de la modification des options de la configuration
+ for (String propertyKey : properties) {
+ // add a listener
+ if (log.isDebugEnabled()) {
+ log.debug("register saveUserAction on property [" +
+ propertyKey + ']');
+ }
+ addPropertyChangeListener(propertyKey, saveUserAction);
+ }
+ } finally {
+
+ // ok back to normal adjusting state
+ setAdjusting(false);
+ }
+ }
+
+ /**
+ * Get all set method on this object or super object.
+ *
+ * @return map with method name without set and in lower case as key, and
+ * method as value
+ */
+ protected Map<String, Method> getMethods() {
+ // looking for all methods set on ApplicationConfig
+ Method[] allMethods = getClass().getMethods();
+ Map<String, Method> methods = new HashMap<String, Method>();
+ for (Method m : allMethods) {
+ String methodName = m.getName();
+ if (methodName.startsWith("set")) {
+ methodName = methodName.substring(3).toLowerCase();
+ methods.put(methodName, m);
+ }
+ }
+ return methods;
+ }
+
+ /**
+ * Take required argument for method in args. Argument used is removed from
+ * args. If method has varArgs, we take all argument to next '--'
+ *
+ * @param m the method to call
+ * @param args iterator with many argument (equals or more than necessary
+ * @return the arguments found for the given method
+ */
+ protected String[] getParams(Method m, ListIterator<String> args) {
+ List<String> result = new ArrayList<String>();
+ if (m.isVarArgs()) {
+ while (args.hasNext()) {
+ String p = args.next();
+ if (p.startsWith("--")) {
+ // stop search
+ args.previous();
+ break;
+ } else {
+ result.add(p);
+ args.remove();
+ }
+ }
+ } else {
+ int paramLenght = m.getParameterTypes().length;
+ for (int i = 0; i < paramLenght; i++) {
+ String p = args.next();
+ args.remove(); // remove this arg because is used now
+ result.add(p);
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ /**
+ * Create action from string, string must be [package.][class][#][method]
+ * if package, class or method missing, default is used
+ *
+ * @param name name of the action
+ * @param args arguments for action invocation
+ * @return the created action
+ * @throws ArgumentsParserException if parsing failed
+ * @throws IllegalAccessException if could not create action
+ * @throws IllegalArgumentException if could not create action
+ * @throws InstantiationException if could not create action
+ * @throws InvocationTargetException if could not create action
+ */
+ protected Action createAction(String name,
+ ListIterator<String> args)
+ throws ArgumentsParserException,
+ InstantiationException,
+ IllegalAccessException,
+ IllegalArgumentException,
+ InvocationTargetException {
+ Action result = null;
+
+ List<Method> methods = ObjectUtil.getMethod(name, true);
+
+ Class clazz = null;
+ Method method = null;
+ if (methods.size() > 0) {
+ if (methods.size() > 1) {
+ log.warn(String.format(
+ "More than one method found, used the first: %s",
+ methods));
+ }
+ method = methods.get(0);
+ clazz = method.getDeclaringClass();
+ }
+
+ if (method != null) {
+ // remove option from command line, because is used now
+ args.remove();
+
+ // creation de l'object sur lequel on fera l'appel
+ Object o = cacheAction.get(clazz);
+ if (o == null && !Modifier.isStatic(method.getModifiers())) {
+ try {
+ o = ConstructorUtils.invokeConstructor(clazz, this);
+ } catch (NoSuchMethodException eee) {
+ log.debug(String.format(
+ "Use default constructor, because no constructor" +
+ " with Config parameter on class %s",
+ clazz.getName()));
+ o = clazz.newInstance();
+ }
+ cacheAction.put(clazz, o);
+ }
+
+ // recherche du step de l'action
+ int step = 0;
+ Action.Step annotation = method.getAnnotation(Action.Step.class);
+ if (annotation != null) {
+ step = annotation.value();
+ }
+
+ String[] params = getParams(method, args);
+ result = new Action(step, o, method, params);
+ }
+
+ return result;
+ }
+
+ /**
+ * Parse option and call set necessary method, read jvm, env variable,
+ * Load configuration file and prepare Action.
+ *
+ * @param args argument as main(String[] args)
+ * @return ApplicationConfig instance
+ * @throws ArgumentsParserException if parsing failed
+ */
+ public ApplicationConfig parse(String... args) throws ArgumentsParserException {
+ if (args == null) {
+ args = ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ try {
+ Map<String, Method> methods = getMethods();
+
+ List<String> arguments = new ArrayList<String>(args.length);
+ for (String arg : args) {
+ if (aliases.containsKey(arg)) {
+ arguments.addAll(aliases.get(arg));
+ } else {
+ arguments.add(arg);
+ }
+ }
+
+ // first parse option
+ inParseOptionPhase = true;
+ for (ListIterator<String> i = arguments.listIterator();
+ i.hasNext(); ) {
+ String arg = i.next();
+ if (arg.equals("--")) {
+ // stop parsing
+ break;
+ }
+ if (arg.startsWith("--")) {
+ String optionName = arg.substring(2);
+ if (methods.containsKey(optionName)) {
+ i.remove(); // remove this arg because is used now
+ Method m = methods.get(optionName);
+ String[] params = getParams(m, i);
+ if (log.isDebugEnabled()) {
+ log.debug(String.format(
+ "Set option '%s' with method '%s %s'",
+ optionName, m, Arrays.toString(params)));
+ }
+ ObjectUtil.call(this, m, params);
+ }
+ }
+ }
+ inParseOptionPhase = false;
+
+ //
+ // second load options from all sources
+ //
+ // JVM
+ jvm.putAll(System.getProperties());
+ // ENV
+ env.putAll(System.getenv());
+
+ // classpath
+ String filename = getConfigFileName();
+ Enumeration<URL> enumInClasspath = ClassLoader.getSystemClassLoader().getResources(filename);
+ Set<URL> urlsInClasspath = new HashSet<URL>(EnumerationUtils.toList(enumInClasspath));
+
+ enumInClasspath = ApplicationConfig.class.getClassLoader().getResources(filename);
+ urlsInClasspath.addAll(EnumerationUtils.toList(enumInClasspath));
+
+ if (log.isDebugEnabled() && urlsInClasspath.isEmpty()) {
+ log.debug("No configuration file found in classpath : /" + filename);
+ }
+
+ for (URL inClasspath : urlsInClasspath) {
+ if (log.isInfoEnabled()) {
+ log.info("Loading configuration file (classpath) : " +
+ inClasspath);
+ }
+ loadResource(inClasspath.toURI(), classpath);
+ }
+
+ // system directory
+ File etcConfig = getSystemConfigFile();
+ if (etcConfig.exists()) {
+ if (log.isInfoEnabled()) {
+ log.info("Loading configuration file (etc) : " + etcConfig);
+ }
+ loadResource(etcConfig.toURI(), etcfile);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("No configuration file found in system : " +
+ etcConfig.getAbsolutePath());
+ }
+ }
+
+ // user home directory
+ File homeConfig = getUserConfigFile();
+ if (log.isDebugEnabled()) {
+ log.debug("User configuration file : " + homeConfig);
+ }
+
+ if (homeConfig.exists()) {
+ if (log.isInfoEnabled()) {
+ log.info("Loading configuration file (home) : " +
+ homeConfig);
+ }
+ loadResource(homeConfig.toURI(), homefile);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("No configuration file found in user home : " +
+ homeConfig.getAbsolutePath());
+ }
+ }
+
+ // file $CURDIR/filename
+ File config = new File(filename);
+ if (config.exists()) {
+ if (log.isInfoEnabled()) {
+ log.info("Loading configuration file (curr) : " + config);
+ }
+ loadResource(config.toURI(), curfile);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("No configuration file found in current" +
+ " directory : " + config.getAbsolutePath());
+ }
+ }
+
+ //
+ // third parse action and do action
+ //
+ for (ListIterator<String> i = arguments.listIterator();
+ i.hasNext(); ) {
+ String arg = i.next();
+ if (arg.equals("--")) {
+ // stop parsing
+ break;
+ }
+ if (arg.startsWith("--")) {
+ String optionName = arg.substring(2);
+ Action action = createAction(optionName, i);
+ addAction(action);
+ }
+ }
+
+ //
+ // not used args added to unparsed
+ //
+ arguments.remove("--");
+ unparsed.addAll(arguments);
+
+ } catch (Exception eee) {
+ if (log.isErrorEnabled()) {
+ log.error(eee);
+ }
+ throw new ArgumentsParserException("Can't parse argument", eee);
+ }
+ return this;
+ }
+
+ /**
+ * Move old user configuration file {@code oldHomeConfig} to {@code
+ * homeConfig}.
+ *
+ * @param oldHomeConfig old configuration file path
+ * @param homeConfig new configuration file path
+ * @throws IOException if could not move configuration file
+ */
+ protected void migrateUserConfigurationFile(File oldHomeConfig,
+ File homeConfig)
+ throws IOException {
+ if (log.isInfoEnabled()) {
+ log.info(_("nuitonutil.config.moving.conf",
+ oldHomeConfig.getPath(), homeConfig.getPath()));
+ }
+
+ boolean b = oldHomeConfig.renameTo(homeConfig);
+ if (!b) {
+ // could not move...
+ String message = String.format(
+ "could not move old configuration file %s to %s",
+ oldHomeConfig,
+ homeConfig
+ );
+ throw new IOException(message);
+ }
+ }
+
+ /**
+ * Load a resources given by his {@code uri} to the given
+ * {@code properties} argument.
+ *
+ * @param uri the uri to load
+ * @param properties the properties file to load
+ * @throws IOException if something occurs bad while loading resource
+ * @see Properties#load(Reader)
+ * @since 2.3
+ */
+ protected void loadResource(URI uri, Properties properties) throws IOException {
+ InputStreamReader reader =
+ new InputStreamReader(uri.toURL().openStream(), getEncoding());
+ try {
+ properties.load(reader);
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * Save the given {@code properties} into the given {@code file} with
+ * the given {@code comment}.
+ *
+ * @param file the location where to store the properties
+ * @param properties the properties file to save
+ * @param comment the comment to add in the saved file
+ * @throws IOException if something occurs bad while saving resource
+ * @see Properties#store(Writer, String)
+ * @since 2.3
+ */
+ protected void saveResource(File file,
+ Properties properties,
+ String comment) throws IOException {
+ Writer reader =
+ new OutputStreamWriter(new FileOutputStream(file), getEncoding());
+ try {
+ properties.store(reader, comment);
+ } finally {
+ reader.close();
+ }
+ }
+
+ /** For debugging. */
+ public void printConfig() {
+ System.out.println("-------------------Value-------------------------");
+ printConfig(System.out);
+ System.out.println("-------------------------------------------------");
+ }
+
+ /**
+ * Print out current configuration in specified output.
+ *
+ * @param output output to write config to
+ * @since 1.1.4
+ */
+ public void printConfig(PrintStream output) {
+ output.println("defaults " + defaults);
+ output.println("classpath " + classpath);
+ output.println("etcfile " + etcfile);
+ output.println("homefile " + homefile);
+ output.println("curfile " + curfile);
+ output.println("env " + env);
+ output.println("jvm " + jvm);
+ output.println("line " + line);
+ output.println("options " + options);
+ }
+
+ /**
+ * Return all configuration used with value, that respect includePattern
+ *
+ * @param includePattern null for all value, or config key pattern (ex: "wikitty.*")
+ * @param padding for better presentation, you can use padding to align '=' sign
+ * @return string that represent config
+ * @since 1.5.2
+ */
+ public String getPrintableConfig(String includePattern, int padding) {
+ String msg = "Configuration:\n";
+ for (String key : getFlatOptions().stringPropertyNames()) {
+ if (includePattern == null || "".equals(includePattern)
+ || key.matches(includePattern)) {
+ String value = getOption(key);
+ msg += String.format("\t%" + padding + "s = %s\n", key, value);
+ }
+ }
+ return msg;
+ }
+
+ protected void firePropertyChange(String propertyName,
+ Object oldValue, Object newValue) {
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ pcs.addPropertyChangeListener(listener);
+ }
+
+ public void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ pcs.addPropertyChangeListener(propertyName, listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ pcs.removePropertyChangeListener(listener);
+ }
+
+ public void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ pcs.removePropertyChangeListener(propertyName, listener);
+ }
+
+ public boolean hasListeners(String propertyName) {
+ return pcs.hasListeners(propertyName);
+ }
+
+ public PropertyChangeListener[] getPropertyChangeListeners(
+ String propertyName) {
+ return pcs.getPropertyChangeListeners(propertyName);
+ }
+
+ public PropertyChangeListener[] getPropertyChangeListeners() {
+ return pcs.getPropertyChangeListeners();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // C L A S S E S D E C L A R A T I O N
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Action to save user configuration.
+ * <p/>
+ * Add it as a listener of the configuration for a given property.
+ * <p/>
+ * <b>Note:</b> Will not save if {@link #isAdjusting()} is {@code true}.
+ *
+ * @since 1.3
+ */
+ private final PropertyChangeListener saveUserAction =
+ new PropertyChangeListener() {
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (isAdjusting()) {
+ if (log.isDebugEnabled()) {
+ log.debug("Skip save while adjusting");
+ }
+ return;
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Saving configuration fired by property [" +
+ evt.getPropertyName() + "] at " +
+ new Date());
+ }
+ saveForUser();
+ }
+ };
+
+ /**
+ * Permet de masquer un prefix. Il est possible d'avoir des valeurs par
+ * defaut. Par exemple:
+ * <pre>
+ * monOption=toto
+ * monPrefix.monOption=titi
+ * </pre>
+ * <p/>
+ * <li>Si on cree le subApp avec le prefix "monPrefix." et qu'on demande la valeur
+ * de "monOption", la valeur retournee est "titi".
+ * <li>Si on cree le subApp avec le prefix "monAutrePrefix." et qu'on demande la valeur
+ * de "monOption", la valeur retournee est "toto" (valeur par defaut de monOption.
+ * <p/>
+ * Certaines methodes retournees ne sont pas
+ * surchargee et ne masque pas le prefix:
+ * <li>getOptions()
+ *
+ * @since 2.4.9
+ */
+ public static class SubApplicationConfig extends ApplicationConfig {
+
+ protected ApplicationConfig parent;
+
+ protected String prefix;
+
+ public SubApplicationConfig(ApplicationConfig parent, String prefix) {
+ this.parent = parent;
+ this.prefix = prefix;
+ }
+
+ @Override
+ protected void init(Properties defaults, String configFilename) {
+ // do nothing
+ }
+
+ public ApplicationConfig getParent() {
+ return parent;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ @Override
+ public Properties getOptions() {
+ return getParent().getOptions();
+ }
+
+ @Override
+ public void setDefaultOption(String key, String value) {
+ getParent().setDefaultOption(getPrefix() + key, value);
+ }
+
+ @Override
+ public boolean hasOption(String key) {
+ boolean result = getOption(key) != null;
+ return result;
+ }
+
+ @Override
+ public void setOption(String key, String value) {
+ getParent().setOption(getPrefix() + key, value);
+ }
+
+ /**
+ * Surcharge pour recherche la cle avec le prefix. Si on ne la retrouve
+ * pas, on recherche sans le prefix pour permettre d'avoir des valeurs
+ * par defaut.
+ *
+ * @param key La cle de l'option
+ * @return l'option trouvé avec le prefix ou sinon celle sans le prefix
+ * si pas trouvé.
+ */
+ @Override
+ public String getOption(String key) {
+ String result = getParent().getOption(getPrefix() + key);
+ if (result == null) {
+ result = getParent().getOption(key);
+ }
+ return result;
+ }
+
+ /**
+ * Surcharge de la methode pour que les options commencant par le prefix
+ * soit modifiee pour qu'elle est la meme cle sans le prefix. Le but
+ * est de garder les autres options et si une option avait le meme nom
+ * qu'elle soit effacee par celle dont on a supprime le prefix
+ *
+ * @param replaceInner le prefix à remplacer
+ * @return les options commencant par le prefix
+ * soit modifiee pour qu'elle est la meme cle sans le prefix. Le but
+ * est de garder les autres options et si une option avait le meme nom
+ * qu'elle soit effacee par celle dont on a supprime le prefix
+ */
+ @Override
+ public Properties getFlatOptions(boolean replaceInner) {
+ Properties result = getParent().getFlatOptions(replaceInner);
+ Properties tmp = new Properties();
+ int lenght = getPrefix().length();
+ for (Map.Entry e : result.entrySet()) {
+ String k = (String) e.getKey();
+ if (k.startsWith(getPrefix())) {
+ k = k.substring(lenght);
+ String v = (String) e.getValue();
+ tmp.setProperty(k, v);
+ }
+ }
+ result.putAll(tmp);
+ return result;
+ }
+
+ /**
+ * Surcharge pour recupere les valeurs commencant par le prefix demande
+ * en plus du prefix 'sub'. Les options sont ensuite fusionnee pour
+ * permettre aussi les valeurs par defaut
+ *
+ * @param prefix prefix to use
+ * @return les valeurs commençant par le prefix demandé en plus du
+ * prefix 'sub'.
+ */
+ @Override
+ public Properties getOptionStartsWith(String prefix) {
+ Properties result = getParent().getOptionStartsWith(prefix);
+ Properties tmp = getParent().getOptionStartsWith(getPrefix() + prefix);
+ int lenght = getPrefix().length();
+ for (Map.Entry e : tmp.entrySet()) {
+ String k = (String) e.getKey();
+ k = k.substring(lenght);
+ String v = (String) e.getValue();
+ // on ajout/ecrase les valeurs de result
+ result.setProperty(k, v);
+ }
+ return result;
+ }
+
+ @Override
+ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+ if (propertyName.startsWith(getPrefix())) {
+ propertyName = propertyName.substring(getPrefix().length());
+ getParent().firePropertyChange(propertyName, oldValue, newValue);
+ } // else not fire event
+ }
+
+ @Override
+ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ getParent().addPropertyChangeListener(getPrefix() + propertyName, listener);
+ }
+
+ @Override
+ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ getParent().removePropertyChangeListener(getPrefix() + propertyName, listener);
+ }
+
+ @Override
+ public boolean hasListeners(String propertyName) {
+ return getParent().hasListeners(getPrefix() + propertyName);
+ }
+
+ // methode interdite dans le sub
+
+ @Override
+ public ApplicationConfig parse(String... args) throws ArgumentsParserException {
+ throw new UnsupportedOperationException("This method is not supported in SubApplicationConfig");
+ }
+
+
+ }
+
+ /**
+ * Le contrat de marquage des options, on utilise cette interface pour
+ * caracteriser une option de configuration.
+ * <p/>
+ * <pre>
+ * public enum MyConfigOption implements OptionDef {
+ *
+ * APP_CONFIG_FILE(
+ * ApplicationConfig.CONFIG_FILE_NAME,
+ * "Main configuration app file",
+ * "myApp-config.properties",
+ * String.class, true, true),
+ *
+ * APP_NAME(
+ * ApplicationConfig.CONFIG_FILE_NAME,
+ * Application name,
+ * "MyApp",
+ * String.class, true, true);
+ *
+ * public String key;
+ * public String description;
+ * public String defaultValue;
+ * public Class<?> type;
+ * public boolean isTransient;
+ * public boolean isFinal;
+ *
+ * private WikittyConfigOption(String key, String description,
+ * String defaultValue, Class<?> type, boolean isTransient, boolean isFinal) {
+ * this.key = key;
+ * this.description = description;
+ * this.defaultValue = defaultValue;
+ * this.type = type;
+ * this.isTransient = isTransient;
+ * this.isFinal = isFinal;
+ * }
+ *
+ * @Override
+ * public boolean isFinal() {
+ * return isFinal;
+ * }
+ *
+ * @Override
+ * public boolean isTransient() {
+ * return isTransient;
+ * }
+ *
+ * @Override
+ * public String getDefaultValue() {
+ * return defaultValue;
+ * }
+ *
+ * @Override
+ * public String getDescription() {
+ * return description;
+ * }
+ *
+ * @Override
+ * public String getKey() {
+ * return key;
+ * }
+ *
+ * @Override
+ * public Class<?> getType() {
+ * return type;
+ * }
+ *
+ * @Override
+ * public void setDefaultValue(String defaultValue) {
+ * this.defaultValue = defaultValue;
+ * }
+ *
+ * @Override
+ * public void setTransient(boolean isTransient) {
+ * this.isTransient = isTransient;
+ * }
+ *
+ * @Override
+ * public void setFinal(boolean isFinal) {
+ * this.isFinal = isFinal;
+ * }
+ * }
+ * </pre>
+ *
+ * @since 1.0.0-rc-9
+ */
+ public interface OptionDef extends Serializable {
+
+ /** @return la clef identifiant l'option */
+ String getKey();
+
+ /** @return le type de l'option */
+ Class<?> getType();
+
+ /** @return la clef i18n de description de l'option */
+ String getDescription();
+
+ /**
+ * @return la valeur par defaut de l'option sous forme de chaine de
+ * caracteres
+ */
+ String getDefaultValue();
+
+ /**
+ * @return <code>true</code> si l'option ne peut etre sauvegardee sur
+ * disque (utile par exemple pour les mots de passe, ...)
+ */
+ boolean isTransient();
+
+ /**
+ * @return <code>true</code> si l'option n'est pas modifiable (utilise
+ * par exemple pour la version de l'application, ...)
+ */
+ boolean isFinal();
+
+ /**
+ * Changes the default value of the option.
+ *
+ * @param defaultValue the new default value of the option
+ */
+ void setDefaultValue(String defaultValue);
+
+ /**
+ * Changes the transient state of the option.
+ *
+ * @param isTransient the new value of the transient state
+ */
+ void setTransient(boolean isTransient);
+
+ /**
+ * Changes the final state of the option.
+ *
+ * @param isFinal the new transient state value
+ */
+ void setFinal(boolean isFinal);
+ }
+
+ /**
+ * Le contrat de marquage des action, on utilise cette interface pour
+ * caracteriser une action.
+ * <p/>
+ * Ex :
+ * <p/>
+ * <pre>
+ * public enum MyAppConfigAction implements ActionDef {
+ * HELP(MyAppHelpAction.class.getName() + "#show", "-h", "--help");
+ * public String action;
+ * public String[] aliases;
+ *
+ * private WikittyConfigAction(String action, String... aliases) {
+ * this.action = action;
+ * this.aliases = aliases;
+ * }
+ *
+ * @Override
+ * public String getAction() {
+ * return action;
+ * }
+ *
+ * @Override
+ * public String[] getAliases() {
+ * return aliases;
+ * }
+ *
+ * }
+ * </pre>
+ *
+ * @author sletellier
+ * @since 1.5.2
+ */
+ public interface ActionDef extends Serializable {
+
+ /**
+ * Must return fully qualified method path : package.Class#method
+ *
+ * @return action to run
+ */
+ String getAction();
+
+ /**
+ * Return all alias used to execute action.
+ *
+ * @return aliases used to execute action
+ */
+ String[] getAliases();
+ }
+
+ /**
+ * Defines a runtime action to be launched via the {@link #doAction()}
+ * method.
+ *
+ * @author poussin
+ */
+ public static class Action {
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface Step {
+
+ int value() default 0;
+ }
+
+ protected int step;
+
+ protected Object o;
+
+ protected Method m;
+
+ protected String[] params;
+
+ public Action(int step, Object o, Method m, String... params) {
+ this.step = step;
+ this.o = o;
+ this.m = m;
+ this.params = params;
+ }
+
+ public void doAction() throws IllegalAccessException,
+ IllegalArgumentException,
+ InvocationTargetException,
+ InstantiationException {
+ ObjectUtil.call(o, m, params);
+ }
+ }
+
+ /**
+ * Item used for cacheOption
+ *
+ * @param <T>
+ */
+ protected static class CacheItem<T> {
+
+ /** typed option value */
+ public T item;
+
+ /** hash of string representation */
+ public int hash;
+
+ public CacheItem(T item, int hash) {
+ this.item = item;
+ this.hash = hash;
+ }
+ }
+
+ public static class OptionList {
+
+ protected ApplicationConfig config;
+
+ protected String key;
+
+ protected String value;
+
+ public OptionList(ApplicationConfig config, String key, String value) {
+ this.config = config;
+ this.key = key;
+ this.value = value;
+ }
+
+ protected <T> List<T> convertListOption(Class<T> type) {
+ List<T> result = (List<T>) config.convertOption(type, key,
+ value,
+ true
+ );
+ return result;
+ }
+
+ /**
+ * Get option value as {@link String}.
+ *
+ * @return value as String
+ */
+ public List<String> getOption() {
+ List<String> result = convertListOption(String.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link File}.
+ *
+ * @return value as file
+ */
+ public List<File> getOptionAsFile() {
+ List<File> tmp = convertListOption(File.class);
+ List<File> result = new ArrayList<File>(tmp.size());
+ for (File file : tmp) {
+ result.add(file.getAbsoluteFile());
+ }
+ return result;
+ }
+
+ /**
+ * Get option value as {@link URL}.
+ *
+ * @return value as URL
+ */
+ public List<URL> getOptionAsURL() {
+ List<URL> result = convertListOption(URL.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Class}.
+ *
+ * @return value as Class
+ */
+ public List<Class> getOptionAsClass() {
+ List<Class> result = convertListOption(Class.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Date}.
+ *
+ * @return value as Date
+ */
+ public List<Date> getOptionAsDate() {
+ List<Date> result = convertListOption(Date.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Time}.
+ *
+ * @return value as Time
+ */
+ public List<Time> getOptionAsTime() {
+ List<Time> result = convertListOption(Time.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@link Timestamp}.
+ *
+ * @return value as Timestamp
+ */
+ public List<Timestamp> getOptionAsTimestamp() {
+ List<Timestamp> result = convertListOption(Timestamp.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@code int}.
+ *
+ * @return value as {@code int}
+ */
+ public List<Integer> getOptionAsInt() {
+ List<Integer> result = convertListOption(Integer.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@code double}.
+ *
+ * @return value as {@code double}
+ */
+ public List<Double> getOptionAsDouble() {
+ List<Double> result = convertListOption(Double.class);
+ return result;
+ }
+
+ /**
+ * Get option value as {@code boolean}.
+ *
+ * @return value as {@code boolean}.
+ */
+ public List<Boolean> getOptionAsBoolean() {
+ List<Boolean> result = convertListOption(Boolean.class);
+ return result;
+ }
+ }
+
+}
Property changes on: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfig.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigHelper.java
===================================================================
--- trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigHelper.java (rev 0)
+++ trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigHelper.java 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,206 @@
+package org.nuiton.util.config;
+
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Config
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2011 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.HashSet;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+/**
+ * Helper about {@link ApplicationConfig}.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.4.8
+ */
+public class ApplicationConfigHelper {
+
+ /** Logger. */
+ private static final Log log =
+ LogFactory.getLog(ApplicationConfigHelper.class);
+
+ protected ApplicationConfigHelper() {
+ // helper with no instance
+ }
+
+ /**
+ * Obtain all providers on class-path.
+ *
+ * @param classLoader optional classLoader used to seek for providers
+ * @param includes optional includes providers to use (if none then accept all providers)
+ * @param excludes optional excludes providers (if none the no reject)
+ * @param verbose verbose flag
+ * @return sets of providers
+ */
+ public static Set<ApplicationConfigProvider> getProviders(ClassLoader classLoader,
+ Set<String> includes,
+ Set<String> excludes,
+ boolean verbose) {
+ ServiceLoader<ApplicationConfigProvider> loader;
+ if (classLoader == null) {
+ loader = ServiceLoader.load(ApplicationConfigProvider.class);
+
+ } else {
+ loader = ServiceLoader.load(ApplicationConfigProvider.class,
+ classLoader);
+ }
+
+ Set<ApplicationConfigProvider> result =
+ new HashSet<ApplicationConfigProvider>();
+
+ for (ApplicationConfigProvider configProvider : loader) {
+ String name = configProvider.getName();
+ if (includes != null && !includes.contains(name)) {
+
+ // reject by include
+ if (verbose) {
+ log.info("configuration named '" + name +
+ "' is rejected by includes.");
+ }
+ continue;
+ }
+ if (excludes != null && excludes.contains(name)) {
+
+ // reject by exclude
+ if (verbose) {
+ log.info("configuration named '" + name +
+ "' is rejected by excludes.");
+ }
+ continue;
+ }
+ if (verbose) {
+ log.info("configuration named '" + name +
+ "' will be generated.");
+ }
+ result.add(configProvider);
+ }
+ return result;
+ }
+
+ public static ApplicationConfigProvider getProvider(ClassLoader classLoader,
+ String name) {
+ Set<ApplicationConfigProvider> providers = getProviders(
+ classLoader, null, null, false);
+ ApplicationConfigProvider result = null;
+ for (ApplicationConfigProvider provider : providers) {
+ if (name.equals(provider.getName())) {
+ result = provider;
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Load default options from all given config providers.
+ *
+ * @param config config where to add default options.
+ * @param providers providers to use
+ * @since 2.6.7
+ */
+ public static void loadAllDefaultOption(ApplicationConfig config,
+ Set<ApplicationConfigProvider> providers) {
+
+ for (ApplicationConfigProvider provider : providers) {
+ if (log.isInfoEnabled()) {
+ log.info("Load default options from configuration: " +
+ provider.getName());
+ }
+ if (log.isInfoEnabled()) {
+ for (ApplicationConfig.OptionDef optionDef : provider.getOptions()) {
+ log.info(" " + optionDef.getKey() +
+ " (" + optionDef.getDefaultValue() + ')');
+ }
+ }
+ config.loadDefaultOptions(provider.getOptions());
+ }
+ }
+
+ /**
+ * Gets all transient options from the given providers.
+ *
+ * @param providers providers to inspect
+ * @return the set of all options that are transient
+ * @see ApplicationConfig.OptionDef#isTransient()
+ * @since 2.6.7
+ */
+ public static Set<ApplicationConfig.OptionDef> getTransientOptions(Set<ApplicationConfigProvider> providers) {
+ Set<ApplicationConfig.OptionDef> result = new HashSet<ApplicationConfig.OptionDef>();
+ for (ApplicationConfigProvider provider : providers) {
+ for (ApplicationConfig.OptionDef def : provider.getOptions()) {
+ if (def.isTransient()) {
+ result.add(def);
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Gets all final options from the given providers.
+ *
+ * @param providers providers to inspect
+ * @return the set of all options that are final
+ * @see ApplicationConfig.OptionDef#isFinal()
+ * @since 2.6.7
+ */
+ public static Set<ApplicationConfig.OptionDef> getFinalOptions(Set<ApplicationConfigProvider> providers) {
+ Set<ApplicationConfig.OptionDef> result = new HashSet<ApplicationConfig.OptionDef>();
+ for (ApplicationConfigProvider provider : providers) {
+ for (ApplicationConfig.OptionDef def : provider.getOptions()) {
+ if (def.isFinal()) {
+ result.add(def);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get all option keys that should not be saved in the user config file
+ * from the given options providers.
+ * <p/>
+ * Such options are {@code transient} or {@code final}.
+ *
+ * @param providers providers to inspect
+ * @return the set of options key not to store in the config file
+ * @see ApplicationConfig.OptionDef#isFinal()
+ * @see ApplicationConfig.OptionDef#isTransient()
+ * @since 2.6.7
+ */
+ public static Set<String> getTransientOrFinalOptionKey(Set<ApplicationConfigProvider> providers) {
+ Set<String> result = new HashSet<String>();
+ for (ApplicationConfig.OptionDef def : getTransientOptions(providers)) {
+ result.add(def.getKey());
+ }
+ for (ApplicationConfig.OptionDef def : getFinalOptions(providers)) {
+ result.add(def.getKey());
+ }
+ return result;
+ }
+}
Property changes on: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigHelper.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigProvider.java
===================================================================
--- trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigProvider.java (rev 0)
+++ trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigProvider.java 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,79 @@
+package org.nuiton.util.config;
+
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Config
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2011 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+
+import java.util.Locale;
+import java.util.ServiceLoader;
+
+/**
+ * Provider of a {@link ApplicationConfig}.
+ * <p/>
+ * Each library of application which use {@link ApplicationConfig} should
+ * implements this and add the provider available via the
+ * {@link ServiceLoader} mecanism.
+ * <p/>
+ * Using such provider offers a nice way to find out what options can be loaded
+ * in a application. It also offers a simply way to generate application
+ * config report for documentation.
+ *
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 1.4.8
+ */
+public interface ApplicationConfigProvider {
+
+ /**
+ * Returns the name of the provided application config.
+ * <p/>
+ * This should be the name of the library or application which offers
+ * the configuration.
+ *
+ * @return the name of the provided application config
+ */
+ String getName();
+
+ /**
+ * Returns the localized description of the configuration.
+ *
+ * @param locale locale used to render description
+ * @return the localized description of the configuration
+ */
+ String getDescription(Locale locale);
+
+ /**
+ * Returns all options offered by the configuration.
+ *
+ * @return all options offered by the configuration
+ * @see ApplicationConfig.OptionDef
+ */
+ ApplicationConfig.OptionDef[] getOptions();
+
+ /**
+ * Returns all actions offered by the configuration.
+ *
+ * @return all actions offered by the configuration.
+ * @see ApplicationConfig.ActionDef
+ */
+ ApplicationConfig.ActionDef[] getActions();
+}
Property changes on: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ApplicationConfigProvider.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Copied: trunk/nuiton-config/src/main/java/org/nuiton/util/config/ArgumentsParserException.java (from rev 2511, trunk/nuiton-utils/src/main/java/org/nuiton/util/ArgumentsParserException.java)
===================================================================
--- trunk/nuiton-config/src/main/java/org/nuiton/util/config/ArgumentsParserException.java (rev 0)
+++ trunk/nuiton-config/src/main/java/org/nuiton/util/config/ArgumentsParserException.java 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,46 @@
+package org.nuiton.util.config;
+
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Config
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2011 - 2013 CodeLutin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+
+/**
+ * Argument parsing exception.
+ *
+ * @author Benjamin Poussin <poussin(a)codelutin.com>
+ * @since 2.7
+ */
+public class ArgumentsParserException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public ArgumentsParserException(String msg) {
+ super(msg);
+ }
+
+ public ArgumentsParserException(String msg, Throwable eee) {
+ super(msg, eee);
+ }
+
+}
+
Added: trunk/nuiton-config/src/main/resources/i18n/nuiton-config_en_GB.properties
===================================================================
--- trunk/nuiton-config/src/main/resources/i18n/nuiton-config_en_GB.properties (rev 0)
+++ trunk/nuiton-config/src/main/resources/i18n/nuiton-config_en_GB.properties 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,2 @@
+nuitonutil.config.moving.conf=Moving old configuration file from %s to %s
+nuitonutil.error.applicationconfig.save=Can't save config in file %s
Property changes on: trunk/nuiton-config/src/main/resources/i18n/nuiton-config_en_GB.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/main/resources/i18n/nuiton-config_es_ES.properties
===================================================================
--- trunk/nuiton-config/src/main/resources/i18n/nuiton-config_es_ES.properties (rev 0)
+++ trunk/nuiton-config/src/main/resources/i18n/nuiton-config_es_ES.properties 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,2 @@
+nuitonutil.config.moving.conf=Colocar el fichero de configuración de %s hacia %s
+nuitonutil.error.applicationconfig.save=Imposible guardar le fichero de configuración en %s
Property changes on: trunk/nuiton-config/src/main/resources/i18n/nuiton-config_es_ES.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/main/resources/i18n/nuiton-config_fr_FR.properties
===================================================================
--- trunk/nuiton-config/src/main/resources/i18n/nuiton-config_fr_FR.properties (rev 0)
+++ trunk/nuiton-config/src/main/resources/i18n/nuiton-config_fr_FR.properties 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,2 @@
+nuitonutil.config.moving.conf=Déplacement du fichier de configuration depuis %s vers %s
+nuitonutil.error.applicationconfig.save=Impossible de sauvegarder le fichier de configuration dans %s
Property changes on: trunk/nuiton-config/src/main/resources/i18n/nuiton-config_fr_FR.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/site/apt/index.apt
===================================================================
--- trunk/nuiton-config/src/site/apt/index.apt (rev 0)
+++ trunk/nuiton-config/src/site/apt/index.apt 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,375 @@
+~~~
+~~ #%L
+~~ Nuiton Utils :: Nuiton Config
+~~ $Id$
+~~ $HeadURL$
+~~ %%
+~~ Copyright (C) 2011 - 2013 CodeLutin
+~~ %%
+~~ This program is free software: you can redistribute it and/or modify
+~~ it under the terms of the GNU Lesser General Public License as
+~~ published by the Free Software Foundation, either version 3 of the
+~~ License, or (at your option) any later version.
+~~
+~~ This program is distributed in the hope that it will be useful,
+~~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+~~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+~~ GNU General Lesser Public License for more details.
+~~
+~~ You should have received a copy of the GNU General Lesser Public
+~~ License along with this program. If not, see
+~~ <http://www.gnu.org/licenses/lgpl-3.0.html>.
+~~ #L%
+~~~
+ ----
+ Nuiton config
+ ----
+ ----
+ 2009-08-23
+ ----
+
+Présentation
+
+ La classe ApplicationConfig a pour but de gérer les options et action
+ disponible au sein d'une application. Elle gère aussi bien :
+
+ * la lecture de fichier de configuration
+
+ * le parsage de la ligne de commande
+
+ * l'execution des actions
+
+ * la sauvegarde de la configuration
+
+
+Lecture/écriture
+
+* Lecture des fichiers de configuration
+
+ La lecture des fichiers de configuration est effectuées lors de l'appel
+ à la methode <<<parse(String...)>>> en utilisant la valeur de
+ <<<getConfigFileName()>>> pour trouver les fichiers à lire.
+
+* La sauvegarde
+
+ La sauvegarde des options se fait via une des trois methodes disponibles :
+
+ * <<<save>>> : sauvegarde dans un fichier specifique
+
+ * <<<saveForSystem>>> : sauvegarde les donnees dans /etc
+
+ * <<<saveForUser>>> : sauvegarde les donnees dans $HOME
+
+ []
+
+ Seules les options qui ont été modifiées par l'application (par la methode
+ <<<setOption()>>> seront sauvegardée. Les variable d'envirronement, les
+ arguments de la ligne de commandes(etc...) ne seront pas sauvegardées.
+
+* Configuration multi instance
+
+ Il est possible d'associé un nom de contexte a une configuration via la
+ methode <<<setAppName("azerty")>>>. Ainsi, les fichiers seront cherchés
+ dans le dossier définit par l'option <<<azerty.config.path>>> si elle existe
+ (sinon, dans le dossier par defaut) et le nom du fichier cherché defini
+ par l'option <<<azerty.config.file>>>.
+
+ Cett option est utilise par exemple pour installer plusieurs instance
+ d'application dans un serveur web et que chaque instance aille
+ chercher ses fichiers de configuration à son propre endroit.
+
+Fonctionnalités
+
+* Les options de configuration
+
+ L'ordre de prise en compte des options suivant les différentes sources est
+ le suivant :
+
+ * Option renseignées par programmation
+
+ * Ligne de commandes
+
+ * Propriétés systèmes (System.getProperties())
+
+ * Propriétés d'envirronement (System.getenv())
+
+ * Fichier du dossier courant ( ./ + nom du fichier)
+
+ * Fichier de configuration globale ( /etc/ + nom du fichier)
+
+ * Fichier dans le classpath ( / + nom du fichier)
+
+ * Valeur par défaut (renseignés à l'init)
+
+ []
+
+ Cela signifie par exemple que si une option à une valeur par défaut, est renseignée
+ dans le fichier /etc et sur la ligne de commande, la valeur presente sur la
+ ligne de commande sera prise en compte.
+
+* Les actions
+
+ Les actions ne peuvent être renseignées que sur la ligne de commande. Exemple :
+
++------------------------------------------------
+--org.nuiton.test.Test#doLogin user password true
++------------------------------------------------
+
+ Une action est donc définie par le chemin complet de la methode qui traitera
+ l'action. Si la methode est statique, elle sera appelée directement. Dans le
+ cas contraire, la classe contenant la methode sera instancié à partir
+ d'un constructeur prenant en parametre seulement la configuration, ou, s'il
+ n'est pas disponible, le constructeur par defaut. La methode sera ensuite
+ appelée sur cette instance. Les divers instances sont conservés pour effectué
+ plusieurs actions.
+
+ Les arguments de la methode sont utilisé lors de l'appel. On sont convertit
+ dans le bon type. Si la méthode avec des arguments de taille variante (...)
+ tous les arguments jusqu'a la prochaine option ou à la fin de la ligne
+ seront utilisé.
+
+ Si vous avez des parametres optionnels, le seul moyen est d'utiliser des
+ arguments variant.
+
+ Par exemple, la ligne de commande précédente appelera la methode
+
++-------------------------------------------
+public class Test {
+ public goLogin(String login, String password, boolean dryRun) {
+ [...]
+ }
+}
++-------------------------------------------
+
+ Les actions ne sont pas executées, mais seulement parsées. Cela signifie
+ qu'elles seront executées seulement lorsque l'application appelera la méthode
+ <<<doAction(int)>>>.
+ Par defaut, toutes les actions sont de niveau 0 et sont executées dans leur
+ ordre d'apparition sur la ligne de commande.
+ Il est possible de differencier les differentes action en utilisant l'annotation
+ <<<@Step>>>
+
++-------------------------------------------
+doAction(0);
+... do something ...
+doAction(1);
++-------------------------------------------
+
+ Dans cet exemple, les actions 0 et 1 ne sont pas effectuées au même moment.
+ C'est très utile par exemple pour executer certaines actions avant le démarrage
+ de l'UI par exemple, et d'autre après...
+
+* Les arguments non parsées
+
+ La configuration 'consome' les arguments de la ligne de commande qu'elle a
+ réussie a traiter. Pour recuperer les autres arguments propres à l'application
+ il est possible de les obtenir grace à la méthode <<<getUnparsed()>>>.
+ Si l'on souhaite forcer la fin du parsing de la ligne de commande il est
+ possible de mettre <<<-->>>.
+
+ Par exemple, la ligne suivante :
+
++-------------------------------------------
+monApplication "mon arg" --option k1 v1 -- --option k2 v2 -- autre
++-------------------------------------------
+
+ Renvera la liste suivante via <<<getUnparsed()>>> :
+
++-------------------------------------------
+"mon arg", "--option", "k2", "v2", "--", "autre"
++-------------------------------------------
+
+* Les alias
+
+ Il est possible d'utiliser des alias pour definir les options et les actions.
+ Ces alias doivent être renseignés par la methode <<<addAlias(String, String>>>:
+
++-------------------------------------------
+addAlias("-v", "--option", "verbose", "true");
+addAlias("-o", "--option", "outputfile");
+addAlias("-i", "--mon.package.MaClass#MaMethode", "import");
++-------------------------------------------
+
+ Lors du parsing de la ligne de commande, tous les alias sont remplacé par
+ leur correspondance. Il est donc possible d'utiliser ce mecanisme pour
+ autre chose :
+
++-------------------------------------------
+addAlias("cl", "Code Lutin");
++-------------------------------------------
+
+ Dans le premier exemple on simplifie une option de flags l'option -v n'attend
+ donc plus d'argument. Dans le second exemple on simplifie une option qui
+ attend encore un argment de type File. Enfin dans le troisieme exemple
+ on simplifie la syntaxe d'une action et on force le premier argument de
+ l'action a etre "import".
+
+
+* Conversion de type
+
+ Pour convertir les types des options et arguments de methodes,
+ {{{http://commons.apache.org/beanutils/}commons-beanutils}} est utilisé.
+
+ Les types actuellement supporté sont :
+
+ * <<<java.lang.String>>>
+
+ * <<<java.io.File>>>
+
+ * <<<java.net.URL>>>
+
+ * <<<java.lang.Class>>>
+
+ * <<<java.sql.Date>>>
+
+ * <<<java.sql.Time>>>
+
+ * <<<java.sql.Timestamp>>>
+
+ * Les tableaux d'un type primitif ou {@link String}. Chaque élément doit
+ être séparé par une virgule.
+
+ []
+
+ Pour utiliser d'autre type, il suffit de le enregistrer dans beanutils via
+ la mézthode <<<ConvertUtils.register(Converter, Class)>>>
+
+* Les substitutions de variable
+
+ La configuration de variable supporte la substitution par d'autre variable
+ via la synthaxe <<<$\{xxx\}>>> où <<<xxx>>> est une autre variable de
+ la configuration
+
+ Par exemple (fichier de configuration):
+
++-------------------------------------------
+application.name = Mon Appli
+application.version = 1.2.3
+application.info = ${application.name} ${application.version} (${java.version})
++-------------------------------------------
+
+ L'appel de l'option <<<application.info>>> via la methode <<<getOption()>>>
+ retournera une chaine de la forme:
+
++-------------------------------------------
+Mon Appli 1.2.3 (1.6.0_18)
++-------------------------------------------
+
+ À noter que les substitutions ne sont remplacée qu'a leur lecture, la sauvegarde
+ de l'option <<<application.info>>> se fera sans remplacement.
+
+Mise en oeuvre
+
+* Définition
+
+ Voici l'ensemble des tâches à effectuer pour définir une configuration
+ d'application :
+
+ * Creation d'une sous classes d'<<<ApplicationConfig>>>
+
+ * Ajout des options par défaut
+
+ * Creation des classes et méthodes d'actions
+
+ * Déclaration des alias des options et actions
+
+ []
+
+ Exemple :
+
++-------------------------------------------
+public class MyConfig extends ApplicationConfig {
+
+ public final static int AFTER_LOGIN = 1;
+
+ public MyConfig () {
+ // options par defaut
+ setDefaultOption("user", "anonymous");
+ setDefaultOption("password", "");
+ // ajout des alias
+ addAlias("-u", "--user");
+ addAlias("-p", "--password");
+ addActionAlias("--login", MyConfig.class.getName + "#" + doLogin");
+ }
+
+ public void setUser(String user) {
+ setOption("user", user);
+ }
+
+ public void setUser(String user) {
+ setOption("user", user);
+ }
+
+ public void doLogin(String user, String password) {
+ [...]
+ }
+
+ @Step(AFTER_LOGIN)
+ public void doSomething() {
+ [...]
+ }
+}
++-------------------------------------------
+
+* Usage
+
+ La configuration doit principalement être initilalisée grâce à la méthode
+ <<<parse(String[])>>> avant d'être utilisé.
+
++-------------------------------------------
+public static void main(String[] args) {
+ MyConfig config = new MyConfig();
+ config.setConfigFileName("myconfig.conf");
+ config.parse(args);
+
+ System.out.println("Connecting with " : + config.getOption("user"));
+ config.doAction(0);
+ System.out.println("Connected, do something...");
+ config.doAction(MyConfig.AFTER_LOGIN);
+}
++-------------------------------------------
+
+* Utilisation du ApplicationConfigProvider
+
+ Ce contrat ajouté en version <2.4.8> permet de spécifier qu'une librairie
+ ou une application offre des options.
+
+ Il suffit d'implanter ce contrat et de le rendre disponible via le mécanisme
+ de ServiceLoader.
+
+** Exemple
+
++-------------------------------------------
+public class PollenApplicationConfigProvider implements ApplicationConfigProvider {
+
+ @Override
+ public String getName() {
+ return "pollen";
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return l_(locale, "pollen.application.config");
+ }
+
+ @Override
+ public ApplicationConfig.OptionDef[] getOptions() {
+ return PollenConfigurationOption.values();
+ }
+
+ @Override
+ public ApplicationConfig.ActionDef[] getActions() {
+ return new ApplicationConfig.ActionDef[0];
+ }
+}
++-------------------------------------------
+
+ Puis ajouter le fichier <META-INF/services/org.nuiton.util.ApplicationConfigProvider>
+ dans les resources du projet :
+
++-------------------------------------------
+org.chorem.pollen.PollenApplicationConfigProvider
++-------------------------------------------
+
+ Cela permet ensuite par exemple de générer un rapport contenant toutes les
+ options disnible dans l'application.
Property changes on: trunk/nuiton-config/src/site/apt/index.apt
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/site/site_fr.xml
===================================================================
--- trunk/nuiton-config/src/site/site_fr.xml (rev 0)
+++ trunk/nuiton-config/src/site/site_fr.xml 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ #%L
+ Nuiton Utils
+
+ $Id$
+ $HeadURL$
+ %%
+ Copyright (C) 2004 - 2010 CodeLutin
+ %%
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Lesser Public License for more details.
+
+ You should have received a copy of the GNU General Lesser Public
+ License along with this program. If not, see
+ <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ #L%
+ -->
+
+<project name="${project.name}">
+
+ <bannerLeft>
+ <name>${project.name}</name>
+ <href>index.html</href>
+ </bannerLeft>
+
+ <body>
+
+ <head>
+ <script type="text/javascript"
+ src="http://maven-site.chorem.org/public/js/mavenpom-site.js">
+ </script>
+
+ <link rel="stylesheet" type="text/css"
+ href="http://maven-site.chorem.org/public/css/mavenpom-site.css"/>
+ </head>
+
+ <breadcrumbs>
+ <item name="${project.name}" href="index.html"/>
+ </breadcrumbs>
+
+ <menu ref="parent"/>
+
+ <menu name="Utilisateur">
+ <item name="Accueil" href="index.html"/>
+ </menu>
+
+ <menu name="Téléchargement">
+ <item
+ href="${repository.home.url}/org/nuiton/${project.artifactId}/${project.version}/${project.build.finalName}.jar"
+ name="Librairie (jar)"/>
+ <item
+ href="${repository.home.url}/org/nuiton/${project.artifactId}/${project.version}/${project.build.finalName}-javadoc.jar"
+ name="Javadoc (jar)"/>
+ <item
+ href="${repository.home.url}/org/nuiton/${project.artifactId}/${project.version}/${project.build.finalName}-sources.jar"
+ name="Sources (jar)"/>
+ </menu>
+
+ <menu ref="reports"/>
+
+ <footer>
+
+ <div id='projectMetas'
+ projectversion='${project.version}'
+ platform='${project.platform}'
+ projectid='${project.projectId}'
+ scm='${project.scm.developerConnection}'
+ scmwebeditorenabled='${project.scmwebeditorEnabled}'
+ scmwebeditorurl='${project.scmwebeditorUrl}'
+ siteSourcesType='${project.siteSourcesType}'
+ piwikEnabled='${project.piwikEnabled}'
+ piwikId='${project.piwikId}' locale='fr'>
+ </div>
+ </footer>
+
+ </body>
+</project>
Property changes on: trunk/nuiton-config/src/site/site_fr.xml
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/test/java/org/nuiton/util/config/ApplicationConfigTest.java
===================================================================
--- trunk/nuiton-config/src/test/java/org/nuiton/util/config/ApplicationConfigTest.java (rev 0)
+++ trunk/nuiton-config/src/test/java/org/nuiton/util/config/ApplicationConfigTest.java 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,660 @@
+package org.nuiton.util.config;
+
+/*
+ * #%L
+ * Nuiton Utils :: Nuiton Config
+ * $Id$
+ * $HeadURL$
+ * %%
+ * Copyright (C) 2011 - 2013 CodeLutin, Tony Chemit
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ */
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.nuiton.util.FileUtil;
+import org.nuiton.util.Version;
+import org.nuiton.util.VersionUtil;
+import org.nuiton.util.config.ApplicationConfig.Action;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * @author Benjamin Poussin <poussin(a)codelutin.com>
+ * @author tchemit <chemit(a)codelutin.com>
+ * @since 2.6.10
+ */
+public class ApplicationConfigTest {
+
+ private static final Log log =
+ LogFactory.getLog(ApplicationConfigTest.class);
+
+ public static final long TIMESTAMP = System.nanoTime();
+
+ protected static int DUMMY_ACTION_CALL;
+
+ public static class DummyAction {
+ @Action.Step(1)
+ public void dummyAction(String s, int step) {
+ DUMMY_ACTION_CALL++;
+ log.info(s + ':' + step);
+ }
+ }
+
+ @Rule
+ public final TestName testName = new TestName();
+
+ protected File testDirectory;
+
+ @Before
+ public void before() {
+ testDirectory = FileUtil.getTestSpecificDirectory(
+ getClass(),
+ testName.getMethodName(),
+ null,
+ TIMESTAMP);
+ }
+
+ @Test
+ public void saveForUser() throws IOException {
+
+ // Initiliaze path and filename
+ String path = testDirectory.getAbsolutePath();
+
+ String oldHome = SystemUtils.getUserHome().getAbsolutePath();
+
+ try {
+ System.setProperty("user.home", path);
+
+ ApplicationConfig config =
+ new ApplicationConfig(testName.getMethodName());
+
+ File userFile = config.getUserConfigFile();
+
+ if (userFile.exists()) {
+ FileUtils.forceDelete(userFile);
+ }
+
+ config.setOption("key1", "toto");
+ config.setOption("key2", "tata");
+ config.setOption("key3", "tutu");
+
+ // Parent directory will be created
+ config.saveForUser();
+
+ // I like to test that file.create works :(
+ Assert.assertTrue(userFile.exists());
+
+ Properties p = loadPropertyFile(userFile);
+
+ Assert.assertEquals(3, p.size());
+
+ String property;
+
+ property = p.getProperty("key1");
+ Assert.assertEquals("toto", property);
+
+ property = p.getProperty("key2");
+ Assert.assertEquals("tata", property);
+
+ property = p.getProperty("key3");
+ Assert.assertEquals("tutu", property);
+
+ } finally {
+
+ if (oldHome != null) {
+ System.setProperty("user.home", oldHome);
+ }
+ }
+
+ }
+
+ @Test
+ public void cleanUserConfig() throws IOException, ArgumentsParserException {
+
+ // Initiliaze path and filename
+ String path = testDirectory.getAbsolutePath();
+
+ String oldHome = SystemUtils.getUserHome().getAbsolutePath();
+
+ try {
+ System.setProperty("user.home", path);
+
+ ApplicationConfig config =
+ new ApplicationConfig(testName.getMethodName());
+
+
+ config.setOption("key1", "toto");
+ config.setOption("key2", "");
+ config.setOption("key3", "tutu");
+
+ File userFile = config.getUserConfigFile();
+
+ Assert.assertTrue(userFile.getAbsolutePath().startsWith(path));
+
+ if (userFile.exists()) {
+ FileUtils.forceDelete(userFile);
+ }
+
+ config.saveForUser();
+
+ Assert.assertTrue(userFile.exists());
+
+ Properties p = loadPropertyFile(userFile);
+
+ Assert.assertEquals(3, p.size());
+
+ String property;
+
+ property = p.getProperty("key1");
+ Assert.assertEquals("toto", property);
+
+ property = p.getProperty("key2");
+ Assert.assertEquals("", property);
+
+ property = p.getProperty("key3");
+ Assert.assertEquals("tutu", property);
+
+ // reload config
+ config = new ApplicationConfig(testName.getMethodName());
+ config.parse();
+
+ config.cleanUserConfig();
+
+ Properties p2 = loadPropertyFile(userFile);
+
+ // key2 was removed
+ Assert.assertEquals(2, p2.size());
+
+ property = p2.getProperty("key1");
+ Assert.assertEquals("toto", property);
+
+ property = p2.getProperty("key2");
+ Assert.assertNull(property);
+
+ property = p2.getProperty("key3");
+ Assert.assertEquals("tutu", property);
+
+ // now key3 will be removed (even if not blank)
+ config.cleanUserConfig("key3");
+
+ // reload config
+ config = new ApplicationConfig(testName.getMethodName());
+ config.parse();
+
+ Properties p3 = loadPropertyFile(userFile);
+
+ // key3 was removed
+ Assert.assertEquals(1, p3.size());
+
+ property = p3.getProperty("key1");
+ Assert.assertEquals("toto", property);
+ } finally {
+
+ if (oldHome != null) {
+ System.setProperty("user.home", oldHome);
+ }
+ }
+
+ }
+
+ @Test
+ public void getUnparsed() throws Exception {
+ ApplicationConfig instance = new ApplicationConfig();
+ List<String> expResult = new ArrayList<String>();
+ List<String> result = instance.getUnparsed();
+ Assert.assertEquals(expResult, result);
+
+ expResult.add("toto");
+ expResult.add("titi");
+ expResult.add("tata");
+
+ instance.parse("toto", "titi", "tata");
+ result = instance.getUnparsed();
+ Assert.assertEquals(expResult, result);
+ }
+
+ @Test
+ public void addAction() throws Exception {
+ Action action = null;
+ ApplicationConfig instance = new ApplicationConfig();
+
+ // test add null Action
+ instance.addAction(action);
+
+ action = new Action(1, new DummyAction(), DummyAction.class.getMethod("dummyAction", String.class, Integer.TYPE), "coucou", "12");
+ instance.addAction(action);
+ }
+
+ @Test
+ public void doAction() throws Exception {
+ ApplicationConfig instance = new ApplicationConfig();
+
+ Action action = new Action(1, new DummyAction(), DummyAction.class.getMethod("dummyAction", String.class, Integer.TYPE), "coucou", "12");
+ instance.addAction(action);
+
+ DUMMY_ACTION_CALL = 0;
+ Assert.assertEquals(0, DUMMY_ACTION_CALL);
+ instance.doAction(0);
+ Assert.assertEquals(0, DUMMY_ACTION_CALL);
+ instance.doAction(1);
+ Assert.assertEquals(1, DUMMY_ACTION_CALL);
+ instance.doAction(2);
+ Assert.assertEquals(1, DUMMY_ACTION_CALL);
+ }
+
+ @Test
+ public void setUseOnlyAliases() {
+ ApplicationConfig instance = new ApplicationConfig();
+ Assert.assertEquals(false, instance.isUseOnlyAliases());
+ instance.setUseOnlyAliases(false);
+ Assert.assertEquals(false, instance.isUseOnlyAliases());
+ instance.setUseOnlyAliases(true);
+ Assert.assertEquals(true, instance.isUseOnlyAliases());
+ }
+
+ @Test
+ public void addAlias() throws Exception {
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.addAlias("toto", "totochange");
+ instance.addAlias("titi", "titichange");
+
+ List<String> expResult = new ArrayList<String>();
+ List<String> result = instance.getUnparsed();
+ Assert.assertEquals(expResult, result);
+
+ expResult.add("totochange");
+ expResult.add("titichange");
+ expResult.add("tata");
+
+ instance.parse("toto", "titi", "tata");
+ result = instance.getUnparsed();
+ Assert.assertEquals(expResult, result);
+ }
+
+ @Test
+ public void testSetConfigFileName() {
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.setConfigFileName("bidulle");
+ Assert.assertEquals("bidulle", instance.getConfigFileName());
+ }
+
+ /** Test of setOption method, of class ApplicationConfig. */
+ @Test
+ public void testSetOption() {
+ ApplicationConfig instance = new ApplicationConfig();
+ Assert.assertEquals(null, instance.getOption("truc"));
+ instance.setOption("truc", "bidulle");
+ Assert.assertEquals("bidulle", instance.getOption("truc"));
+ }
+
+ @Test
+ public void testSubConfig() {
+ ApplicationConfig instance = new ApplicationConfig();
+ Assert.assertEquals(null, instance.getOption("truc"));
+ instance.setOption("truc", "bidulle");
+ instance.setOption("machin", "chouette");
+ instance.setOption("toto.truc", "AutreBidulle");
+ instance.setOption("toto.specific", "theOne");
+ Assert.assertEquals("bidulle", instance.getOption("truc"));
+
+ ApplicationConfig sub = instance.getSubConfig("toto.");
+ // test la surcharge du default
+ Assert.assertEquals("AutreBidulle", sub.getOption("truc"));
+ // test l'utilisation du default
+ Assert.assertEquals("chouette", sub.getOption("machin"));
+ // test une valeur specifique au sub
+ Assert.assertEquals("theOne", sub.getOption("specific"));
+
+ // TODO ajouter d'autres tests, pour les autres methodes surchargee
+ // TODO ajouter d'autres tests pour des sub-(sub-(sub)) config
+ }
+
+ @Test
+ public void getAsList() {
+ List<String> asString = new ArrayList<String>();
+ asString.add(ApplicationConfig.class.getName());
+ asString.add(ApplicationConfigTest.class.getName());
+
+ List<Class> asClass = new ArrayList<Class>();
+ asClass.add(ApplicationConfig.class);
+ asClass.add(ApplicationConfigTest.class);
+
+ ApplicationConfig instance = new ApplicationConfig();
+ Assert.assertEquals(null, instance.getOption("truc"));
+ Assert.assertEquals(Collections.<String>emptyList(), instance.getOptionAsList("truc").getOption());
+
+ instance.setOption("truc", ApplicationConfig.class.getName()
+ + "," + ApplicationConfigTest.class.getName());
+
+ Assert.assertEquals(asString, instance.getOptionAsList("truc").getOption());
+ Assert.assertEquals(asClass, instance.getOptionAsList("truc").getOptionAsClass());
+ }
+
+ @Test
+ public void getMethods() {
+ ApplicationConfig instance = new ApplicationConfig();
+ Map<String, Method> result = instance.getMethods();
+ Assert.assertTrue(result.containsKey("option"));
+ }
+
+ @Test
+ public void getParams() throws Exception {
+ Method m = DummyAction.class.getMethod("dummyAction", String.class, Integer.TYPE);
+ List<String> list = new ArrayList<String>(Arrays.asList("toto", "10", "/tmp", "9"));
+ ListIterator<String> args = list.listIterator();
+
+ ApplicationConfig instance = new ApplicationConfig();
+ String[] expResult = new String[]{"toto", "10"};
+ String[] result = instance.getParams(m, args);
+ Assert.assertEquals(Arrays.asList(expResult), Arrays.asList(result));
+ Assert.assertEquals(2, list.size());
+ }
+
+ @Test
+ public void testCreateAction() throws Exception {
+ List<String> list = new ArrayList<String>(Arrays.asList("dummy", "toto", "10", "/tmp", "9"));
+ ListIterator<String> args = list.listIterator();
+ args.next();
+ ApplicationConfig instance = new ApplicationConfig();
+
+ Action result = instance.createAction(
+ DummyAction.class.getName() + "#dummyAction", args);
+ Assert.assertEquals(1, result.step);
+ DUMMY_ACTION_CALL = 0;
+ result.doAction();
+ Assert.assertEquals(1, DUMMY_ACTION_CALL);
+ }
+
+ @Test
+ public void testParse() throws Exception {
+ String[] args = "-f file -v -d -o /tmp/file -m coucou 10 others args".split(" ");
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.addAlias("-f", "--option", "file");
+ instance.addAlias("-v", "--option", "verbose", "true");
+ instance.addAlias("-d", "--option", "debug", "true");
+ instance.addAlias("-o", "--option", "output");
+ instance.addAlias("-m", "--" + DummyAction.class.getName() + "#dummyAction");
+ instance.parse(args);
+
+ DUMMY_ACTION_CALL = 0;
+ Assert.assertEquals("file", instance.getOption("file"));
+ Assert.assertEquals("true", instance.getOption("verbose"));
+ Assert.assertEquals("true", instance.getOption("debug"));
+ Assert.assertEquals("/tmp/file", instance.getOption("output"));
+ Assert.assertEquals(Arrays.asList("others", "args"), instance.getUnparsed());
+
+ instance.doAction(1);
+ Assert.assertEquals(1, DUMMY_ACTION_CALL);
+ }
+
+ /**
+ * Test that system properties such as ${user.home}, ${user.name} are
+ * replaced.
+ *
+ * @throws ArgumentsParserException
+ */
+ @Test
+ public void testSystemProperties() throws ArgumentsParserException {
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.parse();
+ instance.printConfig();
+
+ instance.setOption("hellomessage", "Hello ${user.name} !");
+
+ Assert.assertEquals("Hello " + System.getProperty("user.name") + " !", instance.getOption("hellomessage"));
+ Assert.assertEquals("Hello ${user.name} !", instance.options.getProperty("hellomessage"));
+
+ instance.setOption("tempdir", "${java.io.tmpdir}" + File.separator + "blah");
+ File tempDir = instance.getOptionAsFile("tempdir");
+ Assert.assertEquals(new File(System.getProperty("java.io.tmpdir"), "blah").getAbsolutePath(), tempDir.getAbsolutePath());
+
+ instance.setOption("system", "${os.name}");
+ instance.setOption("os", "${system}");
+ instance.setOption("sysinfo", "I'm running ${os} :)");
+ Assert.assertEquals("I'm running " + System.getProperty("os.name") + " :)", instance.getOption("sysinfo"));
+
+ // test not found properties
+ instance.setOption("notexists", "Attention ${blah.bloh.bluh} :(");
+ Assert.assertEquals("Attention ${blah.bloh.bluh} :(", instance.getOption("notexists"));
+ }
+
+ /**
+ * test if dot is replaced with _ if properties is not found with dot in env
+ *
+ * @throws ArgumentsParserException
+ */
+ @Test
+ public void testEnvProperties() throws ArgumentsParserException {
+ ApplicationConfig instance = new ApplicationConfig();
+ // simulate env variable with _ to replace dot
+ instance.env.put("test_env", "value");
+
+ String value = instance.getOption("test.env");
+ Assert.assertEquals("value", value);
+ }
+
+ @Test
+ public void getUnparsed2() throws Exception {
+
+ String[] args = "test --du i_am_a_test 2 --option file f1 --option verbose false -- --openui false --m coucou 10 others args".split(" ");
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.addActionAlias("--du", DummyAction.class.getName() + "#" + "dummyAction");
+ instance.parse(args);
+ instance.doAction(1);
+
+ log.info(instance.getUnparsed());
+ Assert.assertEquals(8, instance.getUnparsed().size());
+ Assert.assertEquals("test", instance.getUnparsed().get(0));
+ }
+
+ @Test
+ public void getFlatOptions() throws Exception {
+
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.parse();
+ instance.setDefaultOption("user.firstname", "toto");
+ instance.setDefaultOption("user.lastname", "tutu");
+ instance.setOption("user.fullname", "${user.lastname} ${user.firstname}");
+
+ Assert.assertEquals(1, instance.getOptions().size());
+ // il y en a plus de 3 car il y a aussi les variables d'environnement
+ Assert.assertTrue(instance.getFlatOptions().size() > 3);
+
+ // test replacement and non replacement
+ Assert.assertEquals("tutu toto",
+ instance.getFlatOptions().getProperty("user.fullname"));
+ Assert.assertEquals("tutu toto",
+ instance.getFlatOptions(true).getProperty("user.fullname"));
+ Assert.assertEquals("${user.lastname} ${user.firstname}",
+ instance.getFlatOptions(false).getProperty("user.fullname"));
+ }
+
+ /**
+ * Test null options.
+ * <p/>
+ * TODO EC20100503 this test throw a huge exception
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getNullOptions() throws Exception {
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.parse();
+
+ // primitives can not be null
+ Assert.assertNotNull(instance.getOptionAsBoolean("dfsdfgqsgqfg"));
+ Assert.assertNotNull(instance.getOptionAsDouble("dfsdfgqsgqfg"));
+ Assert.assertNotNull(instance.getOptionAsInt("dfsdfgqsgqfg"));
+ Assert.assertNotNull(instance.getOptionAsLong("dfsdfgqsgqfg"));
+ // list option can not be null
+ Assert.assertNotNull(instance.getOptionAsList("dfsdfgqsgqfg"));
+
+ // all other types can be null
+ Assert.assertNull(instance.getOptionAsClass("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsDate("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsFile("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsLocale("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsTime("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsTimestamp("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsURL("dfsdfgqsgqfg"));
+ Assert.assertNull(instance.getOptionAsVersion("dfsdfgqsgqfg"));
+ }
+
+ /**
+ * Test on printConfig output.
+ *
+ * @throws ArgumentsParserException
+ * @throws UnsupportedEncodingException
+ */
+ public void testxx() throws ArgumentsParserException, UnsupportedEncodingException {
+ ApplicationConfig instance = new ApplicationConfig();
+ instance.parse();
+ instance.setOption("toto", "tata");
+
+ // get content of printConfig
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ try {
+ instance.printConfig(ps);
+ } finally {
+ ps.close();
+ }
+ String content = baos.toString("UTF-8");
+
+ if (log.isDebugEnabled()) {
+ log.debug("printConfig = " + content);
+ }
+
+ Assert.assertTrue(content.indexOf("toto=tata") > 0);
+ }
+
+ @Test
+ public void getOptionAsLocale() {
+ Locale expected;
+ Locale actual;
+
+ ApplicationConfig instance = new ApplicationConfig();
+
+ // test null locale
+ actual = instance.getOptionAsLocale("toto");
+ Assert.assertNull(actual);
+
+ // test not null locale
+ instance.setOption("toto", "fr");
+
+ expected = Locale.FRENCH;
+ actual = instance.getOptionAsLocale("toto");
+ Assert.assertNotNull(actual);
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void getOptionAsVersion() {
+ Version expected;
+ Version actual;
+
+ ApplicationConfig instance = new ApplicationConfig();
+
+ // test null version
+ actual = instance.getOptionAsVersion("toto");
+ Assert.assertNull(actual);
+
+ // not null version
+ instance.setOption("toto", "1.2");
+ expected = VersionUtil.valueOf("1.2");
+ actual = instance.getOptionAsVersion("toto");
+ Assert.assertNotNull(actual);
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void getOptionAsLong() {
+ ApplicationConfig instance = new ApplicationConfig();
+
+ // test long is not null
+ long actual = instance.getOptionAsLong("toto");
+ Assert.assertNotNull(actual);
+ Assert.assertEquals(0l, actual);
+
+ // not null version
+ long expected = System.currentTimeMillis();
+ instance.setOption("toto", "" + expected);
+ actual = instance.getOptionAsLong("toto");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void getOsName() throws Exception {
+ ApplicationConfig config = new ApplicationConfig();
+ config.parse();
+ String v = config.getOsName();
+ Assert.assertTrue(StringUtils.isNotBlank(v));
+ if (log.isInfoEnabled()) {
+ log.info("os.name: " + v);
+ }
+ }
+
+ @Test
+ public void getOsArch() throws Exception {
+ ApplicationConfig config = new ApplicationConfig();
+ config.parse();
+ String v = config.getOsArch();
+ Assert.assertTrue(StringUtils.isNotBlank(v));
+ if (log.isInfoEnabled()) {
+ log.info("os.arch: " + v);
+ }
+ }
+
+ protected Properties loadPropertyFile(File file) throws IOException {
+ FileInputStream inStream;
+
+ inStream = FileUtils.openInputStream(file);
+ try {
+ Properties p = new Properties();
+ p.load(inStream);
+ inStream.close();
+ return p;
+ } finally {
+ IOUtils.closeQuietly(inStream);
+ }
+ }
+
+}
Property changes on: trunk/nuiton-config/src/test/java/org/nuiton/util/config/ApplicationConfigTest.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Added: trunk/nuiton-config/src/test/resources/log4j.properties
===================================================================
--- trunk/nuiton-config/src/test/resources/log4j.properties (rev 0)
+++ trunk/nuiton-config/src/test/resources/log4j.properties 2013-02-26 08:15:50 UTC (rev 2515)
@@ -0,0 +1,33 @@
+###
+# #%L
+# Nuiton Utils :: Nuiton Config
+# $Id$
+# $HeadURL$
+# %%
+# Copyright (C) 2011 - 2013 CodeLutin, Tony Chemit
+# %%
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Lesser Public License for more details.
+#
+# You should have received a copy of the GNU General Lesser Public
+# License along with this program. If not, see
+# <http://www.gnu.org/licenses/lgpl-3.0.html>.
+# #L%
+###
+# Global logging configuration
+log4j.rootLogger=ERROR, stdout
+
+# Console output...
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n
+
+# package level
+log4j.logger.org.nuiton.util.config=INFO
Property changes on: trunk/nuiton-config/src/test/resources/log4j.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: trunk/nuiton-updater/pom.xml
===================================================================
--- trunk/nuiton-updater/pom.xml 2013-02-26 07:51:48 UTC (rev 2514)
+++ trunk/nuiton-updater/pom.xml 2013-02-26 08:15:50 UTC (rev 2515)
@@ -45,6 +45,12 @@
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>nuiton-config</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2013-02-26 07:51:48 UTC (rev 2514)
+++ trunk/pom.xml 2013-02-26 08:15:50 UTC (rev 2515)
@@ -35,6 +35,7 @@
<modules>
<module>nuiton-utils</module>
+ <module>nuiton-config</module>
<module>nuiton-updater</module>
<module>nuiton-csv</module>
<module>nuiton-validator</module>
1
0
r2514 - in trunk/nuiton-utils/src: main/java/org/nuiton/util test/java/org/nuiton/util
by tchemit@users.nuiton.org 26 Feb '13
by tchemit@users.nuiton.org 26 Feb '13
26 Feb '13
Author: tchemit
Date: 2013-02-26 08:51:48 +0100 (Tue, 26 Feb 2013)
New Revision: 2514
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2514
Log:
fixes #2548: At FileUtil#getTestSpecificDirectory method to get a directory to execute write test data
Removed:
trunk/nuiton-utils/src/test/java/org/nuiton/util/TestHelper.java
Modified:
trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/FileUtilTest.java
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java 2013-02-26 07:22:43 UTC (rev 2513)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/FileUtil.java 2013-02-26 07:51:48 UTC (rev 2514)
@@ -37,6 +37,8 @@
package org.nuiton.util;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -1265,4 +1267,40 @@
return result;
}
+ /**
+ * Obtain a directory and creates it if required to place some test data.
+ * <p/>
+ * The directory will be :
+ * <p/>
+ * <pre>
+ * java.io.tmpdir/testclassName.fqn/methodName[/classifier]/timestamp
+ * </pre>
+ *
+ * @param testClassName test class name
+ * @param methodName method name
+ * @param classifier optional classifier
+ * @param timestamp timestamp
+ * @return the computed and created if required directory.
+ * @since 2.6.10
+ */
+ public static File getTestSpecificDirectory(Class<?> testClassName,
+ String methodName,
+ String classifier,
+ long timestamp) {
+ File tempDirFile = SystemUtils.getJavaIoTmpDir();
+
+ // create the directory to store database data
+ String dataBasePath = testClassName.getName()
+ + File.separator // a directory with the test class name
+ + methodName; // a sub-directory with the method name
+
+ if (StringUtils.isNotBlank(classifier)) {
+ dataBasePath += classifier;
+ }
+ dataBasePath += '_'
+ + timestamp; // and a timestamp
+ File databaseFile = new File(tempDirFile, dataBasePath);
+ return databaseFile;
+ }
+
} // FileUtil
Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java 2013-02-26 07:22:43 UTC (rev 2513)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java 2013-02-26 07:51:48 UTC (rev 2514)
@@ -83,8 +83,8 @@
@BeforeClass
public static void setUpClass() {
- // Initialize DIR_TESTS_DATA to target/surefire-data
- DIR_TESTS_DATA = FileUtil.getFileFromFQN(TestHelper.createDefaultTestsDataDirectory(), ApplicationConfigTest.class.getName() + "." + System.nanoTime());
+ // Initialize test data directory
+ DIR_TESTS_DATA = FileUtil.getTestSpecificDirectory(ApplicationConfigTest.class, "", "", System.nanoTime());
oldHome = SystemUtils.getUserHome().getAbsolutePath();
}
Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/FileUtilTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/FileUtilTest.java 2013-02-26 07:22:43 UTC (rev 2513)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/FileUtilTest.java 2013-02-26 07:51:48 UTC (rev 2514)
@@ -5,7 +5,7 @@
* $Id$
* $HeadURL$
* %%
- * Copyright (C) 2004 - 2010 CodeLutin
+ * Copyright (C) 2004 - 2010 CodeLutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,7 +26,10 @@
package org.nuiton.util;
import org.apache.commons.io.FileUtils;
-import org.junit.*;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
import org.junit.rules.TestName;
import java.io.File;
@@ -40,12 +43,26 @@
* Created: 22 nov. 2004
*
* @author Benjamin Poussin <poussin(a)codelutin.com>
+ * @author tchemit <chemit(a)codelutin.com>
*/
public class FileUtilTest { // FileUtilTest
+ public static final long TIMESTAMP = System.nanoTime();
+
@Rule
public final TestName testName = new TestName();
+ protected File parent;
+
+ @Before
+ public void setUp() throws Exception {
+
+ parent = FileUtil.getTestSpecificDirectory(
+ getClass(),
+ testName.getMethodName(), null, TIMESTAMP);
+
+ }
+
@Test
public void testFind() throws Exception {
List<File> result = FileUtil.find(new File("."), ".*FileUtil.*", true);
@@ -238,14 +255,6 @@
FileUtils.deleteDirectory(testDirectory);
}
- static File parent;
-
- @BeforeClass
- public static void beforeTest() {
- parent = TestHelper.createTestsDataDirectory(
- "surefire-workdir" + File.separator + "FileUtil");
- }
-
public void testChangeExtension() throws IOException {
String name = "toto.yo";
String exepectedName = "toto.ya";
@@ -276,17 +285,15 @@
@Test
public void testGetFileFromPaths() {
- File rootDirectory = TestHelper.getBaseDir();
- File actual = FileUtil.getFileFromPaths(rootDirectory, "target", "surefire-workdir", "FileUtil");
- File expected = new File(rootDirectory, "target" + File.separator + "surefire-workdir" + File.separator + "FileUtil");
+ File actual = FileUtil.getFileFromPaths(parent, "target", "surefire-workdir", "FileUtil");
+ File expected = new File(parent, "target" + File.separator + "surefire-workdir" + File.separator + "FileUtil");
Assert.assertEquals(expected, actual);
}
@Test
public void testGetFileFromFQN() {
- File rootDirectory = TestHelper.getBaseDir();
- File actual = FileUtil.getFileFromFQN(rootDirectory, "target.surefire-workdir.FileUtil");
- File expected = new File(rootDirectory, "target" + File.separator + "surefire-workdir" + File.separator + "FileUtil");
+ File actual = FileUtil.getFileFromFQN(parent, "target.surefire-workdir.FileUtil");
+ File expected = new File(parent, "target" + File.separator + "surefire-workdir" + File.separator + "FileUtil");
Assert.assertEquals(expected, actual);
}
Deleted: trunk/nuiton-utils/src/test/java/org/nuiton/util/TestHelper.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/TestHelper.java 2013-02-26 07:22:43 UTC (rev 2513)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/TestHelper.java 2013-02-26 07:51:48 UTC (rev 2514)
@@ -1,102 +0,0 @@
-/*
- * #%L
- * Nuiton Utils :: Nuiton Utils
- *
- * $Id$
- * $HeadURL$
- * %%
- * Copyright (C) 2004 - 2011 CodeLutin
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Lesser Public License for more details.
- *
- * You should have received a copy of the GNU General Lesser Public
- * License along with this program. If not, see
- * <http://www.gnu.org/licenses/lgpl-3.0.html>.
- * #L%
- */
-package org.nuiton.util;
-
-import org.apache.commons.logging.*;
-import org.apache.commons.logging.Log;
-import org.junit.Ignore;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Usefeull methods to do tests.
- *
- * @author tchemit <chemit(a)codelutin.com>
- * @since 2.0
- */
-@Ignore
-public class TestHelper {
-
- private static Log log = LogFactory.getLog(TestHelper.class);
-
- public static final String TESTS_DATA_DEFAULT_DIR = "surefire-workdir";
-
- /**
- * Create a directory in target directory for maven projects. The
- * directory name will be the default one defined by {@link #TESTS_DATA_DEFAULT_DIR}
- *
- * @return the directory created
- * @see #createTestsDataDirectory(String)
- */
- public static File createDefaultTestsDataDirectory() {
- return createTestsDataDirectory(TESTS_DATA_DEFAULT_DIR);
- }
-
- /**
- * Create a directory in target directory for maven projects. The
- * directory will be called {@code dirName}. This directory will be useful
- * to put all data created during tests.
- *
- * @param dirName name of the directory to create
- * @return the directory created
- */
- public static File createTestsDataDirectory(String dirName) {
- // Search basedir from maven environment
- String basedirPath = System.getenv("basedir");
- if (basedirPath == null) {
- basedirPath = new File("").getAbsolutePath();
- }
-
- File result = new File(basedirPath, "target" + File.separator + dirName);
-
- try {
- FileUtil.createDirectoryIfNecessary(result);
- } catch (IOException eee) {
- String errorMessage = "Error during tests data directory creation";
- if (log.isErrorEnabled()) {
- log.error(errorMessage, eee);
- }
- throw new Error(errorMessage, eee);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Create tests data directory : " + result.getAbsolutePath());
- }
-
- return result;
- }
-
- public static File getBaseDir() {
- // Search basedir from maven environment
- String basedirPath = System.getenv("basedir");
- if (basedirPath == null) {
- basedirPath = new File("").getAbsolutePath();
- }
-
- File result = new File(basedirPath);
- return result;
- }
-}
1
0
r2513 - in trunk/nuiton-utils/src: main/java/org/nuiton/util test/java/org/nuiton/util
by tchemit@users.nuiton.org 26 Feb '13
by tchemit@users.nuiton.org 26 Feb '13
26 Feb '13
Author: tchemit
Date: 2013-02-26 08:22:43 +0100 (Tue, 26 Feb 2013)
New Revision: 2513
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2513
Log:
fixes #2543: Deprecates ApplicationConfig
Modified:
trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigProvider.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java
trunk/nuiton-utils/src/main/java/org/nuiton/util/ArgumentsParserException.java
trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java 2013-02-25 15:42:29 UTC (rev 2512)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java 2013-02-26 07:22:43 UTC (rev 2513)
@@ -297,7 +297,10 @@
* <p/>
* Last update $Date$ by
* @since 0.30
+ * @deprecated since 2.6.10 (replaced by org.nuiton.util.config.ApplicationConfig
+ * in nuiton-config module), will be removed in version 2.7.1.
*/
+@Deprecated
public class ApplicationConfig {
/** Logger. */
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java 2013-02-25 15:42:29 UTC (rev 2512)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java 2013-02-26 07:22:43 UTC (rev 2513)
@@ -36,7 +36,10 @@
*
* @author tchemit <chemit(a)codelutin.com>
* @since 2.4.8
+ * @deprecated since 2.6.10 (replaced by org.nuiton.util.config.ApplicationConfigConfigHelper
+ * in nuiton-config module), will be removed in version 2.7.1.
*/
+@Deprecated
public class ApplicationConfigHelper {
/** Logger. */
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigProvider.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigProvider.java 2013-02-25 15:42:29 UTC (rev 2512)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigProvider.java 2013-02-26 07:22:43 UTC (rev 2513)
@@ -40,7 +40,10 @@
*
* @author tchemit <chemit(a)codelutin.com>
* @since 1.4.8
+ * @deprecated since 2.6.10 (replaced by org.nuiton.util.config.ApplicationConfigProvider
+ * in nuiton-config module), will be removed in version 2.7.1.
*/
+@Deprecated
public interface ApplicationConfigProvider {
/**
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java 2013-02-25 15:42:29 UTC (rev 2512)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java 2013-02-26 07:22:43 UTC (rev 2513)
@@ -127,7 +127,7 @@
* by : $Author$
*
* @since 2.6.6
- * @deprecated since 2.7 (replaced by org.nuiton.util.updater.ApplicationUpdater
+ * @deprecated since 2.6.10 (replaced by org.nuiton.util.updater.ApplicationUpdater
* in nuiton-updater module), will be removed in version 2.7.1.
*/
@Deprecated
Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ArgumentsParserException.java
===================================================================
--- trunk/nuiton-utils/src/main/java/org/nuiton/util/ArgumentsParserException.java 2013-02-25 15:42:29 UTC (rev 2512)
+++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ArgumentsParserException.java 2013-02-26 07:22:43 UTC (rev 2513)
@@ -29,12 +29,10 @@
* Argument parsing exception.
*
* @author Benjamin Poussin <poussin(a)codelutin.com>
- * Copyright Code Lutin
- * @version $Revision$
- * <p/>
- * Mise a jour: $Date$
- * par :
+ * @deprecated since 2.6.10 (replaced by org.nuiton.util.config.ArgumentsParserException
+ * in nuiton-config module), will be removed in version 2.7.1.
*/
+@Deprecated
public class ArgumentsParserException extends Exception { // ArgumentsParserException
/** serialVersionUID. */
Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java
===================================================================
--- trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java 2013-02-25 15:42:29 UTC (rev 2512)
+++ trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationConfigTest.java 2013-02-26 07:22:43 UTC (rev 2513)
@@ -27,6 +27,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -53,9 +54,13 @@
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
-import org.apache.commons.lang3.StringUtils;
-/** @author poussin */
+/**
+ * @author poussin
+ * @deprecated since 2.6.10 (replaced by org.nuiton.util.config.ApplicationConfigTest
+ * in nuiton-config module), will be removed in version 2.7.1.
+ */
+@Deprecated
public class ApplicationConfigTest {
private static final Log log =
@@ -507,7 +512,8 @@
/**
* test if dot is replaced with _ if properties is not found with dot in env
- * @throws ArgumentsParserException
+ *
+ * @throws ArgumentsParserException
*/
@Test
public void testEnvProperties() throws ArgumentsParserException {
1
0
r2512 - trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/field
by tchemit@users.nuiton.org 25 Feb '13
by tchemit@users.nuiton.org 25 Feb '13
25 Feb '13
Author: tchemit
Date: 2013-02-25 16:42:29 +0100 (Mon, 25 Feb 2013)
New Revision: 2512
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2512
Log:
fixes #2545: org.nuiton.validator.xwork2.field.CollectionUniqueKeyValidator does not work
Modified:
trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java
Modified: trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java
===================================================================
--- trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java 2013-02-24 10:50:12 UTC (rev 2511)
+++ trunk/nuiton-validator/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java 2013-02-25 15:42:29 UTC (rev 2512)
@@ -170,7 +170,7 @@
if (againstIndex == null) {
againstIndex = -1;
}
- if (againstBean == null && col.size() < 2) {
+ if (!againstMe && againstBean == null && col.size() < 2) {
// la liste ne contient pas deux entrées donc c'est valide
return;
}
1
0
r2511 - in trunk/nuiton-updater/src: main/java/org/nuiton/util/updater site site/apt test/java/org/nuiton/util/updater test/resources
by tchemit@users.nuiton.org 24 Feb '13
by tchemit@users.nuiton.org 24 Feb '13
24 Feb '13
Author: tchemit
Date: 2013-02-24 11:50:12 +0100 (Sun, 24 Feb 2013)
New Revision: 2511
Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2511
Log:
update link and headers
Modified:
trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationInfo.java
trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java
trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdaterCallback.java
trunk/nuiton-updater/src/site/apt/index.apt
trunk/nuiton-updater/src/site/site_fr.xml
trunk/nuiton-updater/src/test/java/org/nuiton/util/updater/ApplicationUpdaterTest.java
trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkAuthTest.properties
trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkTest.properties
trunk/nuiton-updater/src/test/resources/ApplicationUpdaterTest.properties
trunk/nuiton-updater/src/test/resources/log4j.properties
Modified: trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationInfo.java
===================================================================
--- trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationInfo.java 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationInfo.java 2013-02-24 10:50:12 UTC (rev 2511)
@@ -6,7 +6,7 @@
* $Id$
* $HeadURL$
* %%
- * Copyright (C) 2013 CodeLutin
+ * Copyright (C) 2013 CodeLutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Modified: trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java
===================================================================
--- trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdater.java 2013-02-24 10:50:12 UTC (rev 2511)
@@ -6,7 +6,7 @@
* $Id$
* $HeadURL$
* %%
- * Copyright (C) 2013 CodeLutin
+ * Copyright (C) 2013 CodeLutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Modified: trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdaterCallback.java
===================================================================
--- trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdaterCallback.java 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/main/java/org/nuiton/util/updater/ApplicationUpdaterCallback.java 2013-02-24 10:50:12 UTC (rev 2511)
@@ -6,7 +6,7 @@
* $Id$
* $HeadURL$
* %%
- * Copyright (C) 2013 CodeLutin
+ * Copyright (C) 2013 CodeLutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -68,17 +68,13 @@
void startUpdate(ApplicationInfo info);
/**
- * Appeler une fois qu'une mise a jour a parfaitement fonctionne
+ * Appeler une fois qu'une mise a jour a parfaitement fonctionné.
*
- * @param name le nom de l'application
- * @param oldVersion l'ancienne version
- * @param newVersion la nouvelle version
- * @param applicationURL l'url d'ou provient le zip de l'application
- * @param dest le repertoire ou se trouve la nouvelle version
+ * @param appToUpdate le dictionnaire des applications mises à jour
+ * @param appUpdateError le dictionnaires des erreurs rencontrées lors des mises à jour
*/
- void updateDone(
- Map<String, ApplicationInfo> appToUpdate,
- Map<String, Exception> appUpdateError);
+ void updateDone(Map<String, ApplicationInfo> appToUpdate,
+ Map<String, Exception> appUpdateError);
/**
* Called when exception occur during process initialization
Modified: trunk/nuiton-updater/src/site/apt/index.apt
===================================================================
--- trunk/nuiton-updater/src/site/apt/index.apt 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/site/apt/index.apt 2013-02-24 10:50:12 UTC (rev 2511)
@@ -1,3 +1,10 @@
+ ----
+ Nuiton updater
+ ----
+ ----
+ 2013-02-24
+ ----
+
~~~
~~ #%L
~~ Nuiton Utils :: Nuiton Updater
@@ -4,31 +11,24 @@
~~ $Id$
~~ $HeadURL$
~~ %%
-~~ Copyright (C) 2013 CodeLutin
+~~ Copyright (C) 2013 CodeLutin,Tony Chemit
~~ %%
~~ This program is free software: you can redistribute it and/or modify
-~~ it under the terms of the GNU Lesser General Public License as
-~~ published by the Free Software Foundation, either version 3 of the
+~~ it under the terms of the GNU Lesser General Public License as
+~~ published by the Free Software Foundation, either version 3 of the
~~ License, or (at your option) any later version.
-~~
+~~
~~ This program is distributed in the hope that it will be useful,
~~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~~ GNU General Lesser Public License for more details.
-~~
-~~ You should have received a copy of the GNU General Lesser Public
+~~
+~~ You should have received a copy of the GNU General Lesser Public
~~ License along with this program. If not, see
~~ <http://www.gnu.org/licenses/lgpl-3.0.html>.
~~ #L%
~~~
- ----
- Nuiton updater
- ----
- ----
- 2013-02-24
- ----
-
Présentation
TODO
Modified: trunk/nuiton-updater/src/site/site_fr.xml
===================================================================
--- trunk/nuiton-updater/src/site/site_fr.xml 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/site/site_fr.xml 2013-02-24 10:50:12 UTC (rev 2511)
@@ -5,7 +5,7 @@
$Id$
$HeadURL$
%%
- Copyright (C) 2013 CodeLutin
+ Copyright (C) 2013 CodeLutin,Tony Chemit
%%
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
Modified: trunk/nuiton-updater/src/test/java/org/nuiton/util/updater/ApplicationUpdaterTest.java
===================================================================
--- trunk/nuiton-updater/src/test/java/org/nuiton/util/updater/ApplicationUpdaterTest.java 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/test/java/org/nuiton/util/updater/ApplicationUpdaterTest.java 2013-02-24 10:50:12 UTC (rev 2511)
@@ -6,7 +6,7 @@
* $Id$
* $HeadURL$
* %%
- * Copyright (C) 2013 CodeLutin
+ * Copyright (C) 2013 CodeLutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Modified: trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkAuthTest.properties
===================================================================
--- trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkAuthTest.properties 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkAuthTest.properties 2013-02-24 10:50:12 UTC (rev 2511)
@@ -1,10 +1,10 @@
###
# #%L
-# Nuiton Utils :: Nuiton Utils
+# Nuiton Utils :: Nuiton Updater
# $Id$
# $HeadURL$
# %%
-# Copyright (C) 2004 - 2013 CodeLutin
+# Copyright (C) 2013 CodeLutin, Tony Chemit
# %%
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
Modified: trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkTest.properties
===================================================================
--- trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkTest.properties 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/test/resources/ApplicationUpdaterNetworkTest.properties 2013-02-24 10:50:12 UTC (rev 2511)
@@ -1,10 +1,10 @@
###
# #%L
-# Nuiton Utils :: Nuiton Utils
+# Nuiton Utils :: Nuiton Updater
# $Id$
# $HeadURL$
# %%
-# Copyright (C) 2004 - 2013 CodeLutin
+# Copyright (C) 2013 CodeLutin, Tony Chemit
# %%
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
@@ -22,8 +22,8 @@
# #L%
###
App1.version=0.3
-App1.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources/ApplicationUpdater/zip/App1-0.3.zip
+App1.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-updater/src/test/resources/ApplicationUpdater/zip/App1-0.3.zip
linux.App3.version=8
-linux.App3.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources/ApplicationUpdater/zip/App3-7.zip
+linux.App3.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-updater/src/test/resources/ApplicationUpdater/zip/App3-7.zip
linux.amd64.App2.version=7
-linux.amd64.App2.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources/ApplicationUpdater/zip/App2-7.zip
+linux.amd64.App2.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-updater/src/test/resources/ApplicationUpdater/zip/App2-7.zip
Modified: trunk/nuiton-updater/src/test/resources/ApplicationUpdaterTest.properties
===================================================================
--- trunk/nuiton-updater/src/test/resources/ApplicationUpdaterTest.properties 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/test/resources/ApplicationUpdaterTest.properties 2013-02-24 10:50:12 UTC (rev 2511)
@@ -1,10 +1,10 @@
###
# #%L
-# Nuiton Utils :: Nuiton Utils
+# Nuiton Utils :: Nuiton Updater
# $Id$
# $HeadURL$
# %%
-# Copyright (C) 2004 - 2013 CodeLutin
+# Copyright (C) 2013 CodeLutin, Tony Chemit
# %%
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
Modified: trunk/nuiton-updater/src/test/resources/log4j.properties
===================================================================
--- trunk/nuiton-updater/src/test/resources/log4j.properties 2013-02-24 10:39:44 UTC (rev 2510)
+++ trunk/nuiton-updater/src/test/resources/log4j.properties 2013-02-24 10:50:12 UTC (rev 2511)
@@ -1,11 +1,10 @@
###
# #%L
-# Nuiton Utils
-#
+# Nuiton Utils :: Nuiton Updater
# $Id$
# $HeadURL$
# %%
-# Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric
+# Copyright (C) 2013 CodeLutin, Tony Chemit
# %%
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
@@ -31,4 +30,4 @@
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n
# package level
-log4j.logger.org.nuiton.util=INFO
+log4j.logger.org.nuiton.util.updater=INFO
1
0