This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository nuiton-config. See https://gitlab.nuiton.org/nuiton/nuiton-config.git commit 592db202be51ba08bd5e7d42839aa950c29e3377 Author: Tony CHEMIT <chemit@codelutin.com> Date: Fri Oct 7 12:04:28 2016 +0200 Separate io operations from ApplicationConfig --- .../java/org/nuiton/config/ApplicationConfig.java | 108 ++++++++++++--------- .../org/nuiton/config/ApplicationConfigInit.java | 15 +++ .../org/nuiton/config/io/ApplicationConfigIO.java | 21 ++++ .../config/io/ApplicationConfigReadFormat.java | 9 ++ .../ApplicationConfigReadPropertiesException.java | 17 ++++ .../ApplicationConfigWritePropertiesException.java | 17 ++++ .../org/nuiton/config/io/ApplicationIOHelper.java | 49 ++++++++++ 7 files changed, 188 insertions(+), 48 deletions(-) diff --git a/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfig.java b/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfig.java index 0974377..2431f10 100644 --- a/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfig.java +++ b/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfig.java @@ -22,6 +22,7 @@ package org.nuiton.config; * #L% */ +import com.google.common.base.Preconditions; import org.apache.commons.beanutils.ConstructorUtils; import org.apache.commons.collections4.EnumerationUtils; import org.apache.commons.io.FileUtils; @@ -29,6 +30,7 @@ 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.config.io.ApplicationIOHelper; import org.nuiton.converter.ConverterUtil; import org.nuiton.util.ObjectUtil; import org.nuiton.util.RecursiveProperties; @@ -41,11 +43,8 @@ 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.Writer; @@ -80,15 +79,15 @@ import java.util.Set; * Application configuration. * <h3>A finir...</h3> * <ul> - * <li>Ajout d'annotations sur les methodes + * <li>Ajout d'annotations sur les méthodes * 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. + * generer l'aide en ligne. Pour eviter de devoir maintenir une méthode + * dans lequel est écrit 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 + * <li>Vu qu'en java on ne peut pas pointer une méthode mais seulement une classe + * il y a un bout des actions qui sont des chaînes (nom de la méthode). 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)} @@ -125,24 +124,24 @@ import java.util.Set; * </ul> * <h3>Lecture des fichiers de configuration</h3> * <p> - * La lecture des fichiers de configuration se fait durant l'appel de la methode + * La lecture des fichiers de configuration se fait durant l'appel de la méthode * {@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 : + * La sauvegarde des options se fait via une des trois méthodes 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 + * <li> {@link #saveForSystem(String...)} sauvegarde les données dans /etc + * <li> {@link #saveForUser(String...)} sauvegarde les données 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. + * options passees sur la ligne de commande ne seront pas sauvées. * </p> * <h3>Les options de configuration</h3> * <p> @@ -151,7 +150,7 @@ import java.util.Set; * 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>options ajoutées 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> @@ -159,7 +158,7 @@ import java.util.Set; * <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 #setDefaultOption(String, String)}</li> + * <li>options ajoutées par programmation: {@link #setDefaultOption(String, String)}</li> * </ul> * <p> * Les options sur la ligne de commande sont de la forme: @@ -170,8 +169,8 @@ import java.util.Set; * <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 + * méthode setMonOption(key, value1, value2) sur votre classe de configuration + * qui hérite 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> @@ -183,35 +182,35 @@ import java.util.Set; * --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 + * Une action est donc défini par le chemin complet vers la méthode qui traitera + * l'action. Cette méthode peut-être une méthode static ou non. Si la méthode * 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 + * paramètre du constructeur la classe de configuration utilisée 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 + * constructeur avec comme seul paramètre une classe héritant de + * {@link ApplicationConfig} n'existe alors le constructeur par défaut est + * utilise (il doit être accessible). Toutes methodes d'actions faisant * parties d'un meme objet utiliseront la meme instance de cette objet lors * de leur execution. * </p> * <p> - * Si la methode utilise les arguments variants alors tous les arguments + * Si la méthode 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. + * Le nombre exact d'argument nécessaire a la méthode sont utilises. * </p> * <p> - * Les arguments sont automatiquement converti dans le bon type reclame par la + * Les arguments sont automatiquement converti dans le bon type réclamé par la * methode. * </p> * <p> * Si l'on veut des arguments optionnels le seul moyen actuellement est - * d'utiliser une methode avec des arguments variants + * d'utiliser une méthode avec des arguments variants * </p> * <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 + * Les actions ne sont pas execute mais seulement parsées. Pour les exécuter + * il faut utiliser la méthode {@link #doAction(int)} qui prend en argument un numéro * 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 + * Par défaut toutes les actions sont de niveau 0 et sont exécutées * 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 @@ -227,7 +226,7 @@ import java.util.Set; * </p> * <h3>Les arguments non parsées</h3> * <p> - * Tout ce qui n'est pas option ou action est considere comme non parse et peut + * Tout ce qui n'est pas option ou action est considèré 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: @@ -235,16 +234,16 @@ import java.util.Set; * monProg "mon arg" --option k1 v1 -- --option k2 v2 -- autre * </pre> * <p> - * Dans cet exemple seule la premiere option sera considere comme une option. + * Dans cet exemple seule la premiere option sera considère comme une option. * On retrouvera dans {@code unparsed}: "mon arg", "--option", "k2", "v2", "--", * "autre" * </p> * <h3>Les alias</h3> * <p> * 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 + * méthode doit être utilise. Pour éviter ceci il est possible de définir * des alias ce qui permet de creer des options courtes par exemple. Pour cela, - * on utilise la methode {@link #addAlias(String, String...)}. + * on utilise la méthode {@link #addAlias(String, String...)}. * <pre> * addAlias("-v", "--option", "verbose", "true"); * addAlias("-o", "--option", "outputfile"); @@ -252,16 +251,16 @@ import java.util.Set; * </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: + * d'utiliser ce mécanisme pour autre chose par exemple: * <pre> * addAlias("cl", "Code Lutin"); * addAlias("bp", "Benjamin POUSSIN); * </pre> * <p>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 + * attend encore un argument de type File. Enfin dans le troisième exemple * on simplifie la syntaxe d'une action et on force le premier argument de - * l'action a etre "import". + * l'action a être "import". * </p> * <h3>Conversion de type</h3> * <p> @@ -279,12 +278,12 @@ import java.util.Set; * etre separe par une virgule. * </ul> * <p> - * Pour suporter d'autre type, il vous suffit d'enregistrer de nouveau + * Pour supporter d'autre type, il vous suffit d'enregistrer de nouveau * converter dans commons-beans. * </p> * <h3>Les substitutions de variable</h3> * <p> - * {@link ApplicationConfig} supporte les substition de variables de la forme + * {@link ApplicationConfig} supporte les substituions de variables de la forme * <tt>${xxx}</tt> où {@code xxx} est une autre variable de la configuration. * </p> * <p> @@ -415,6 +414,12 @@ public class ApplicationConfig { protected Map<String, Object> context = new HashMap<>(); /** + * Pour gérer la lecture/écriture des properties. + * @since 3.1 + */ + protected ApplicationIOHelper applicationIOHelper; + + /** * Init ApplicationConfig with current simple class name as config file. * <p> * Also init converters. @@ -456,9 +461,9 @@ public class ApplicationConfig { * @since 2.4.8 */ public ApplicationConfig(Properties defaults, String configFilename) { - this(ApplicationConfigInit.forAllScopes() - .setConfigFileName(configFilename) - .setDefaults(defaults)); + this(ApplicationConfigInit.defaultInit() + .setConfigFileName(configFilename) + .setDefaults(defaults)); } /** @@ -479,6 +484,10 @@ public class ApplicationConfig { */ protected void init(ApplicationConfigInit init) { + Preconditions.checkNotNull(init,"Can't init ApplicationConfig without an init paramter"); + Preconditions.checkNotNull(init.getReadFormat(), "Can't init Application without an init.readFormat parameter"); + applicationIOHelper = new ApplicationIOHelper(init.getReadFormat()); + Set<ApplicationConfigScope> scopes = init.getScopes(); Properties lastProperties = null; @@ -2297,9 +2306,11 @@ public class ApplicationConfig { * @since 2.3 */ protected void loadResource(URI uri, Properties properties) throws IOException { - try (InputStreamReader reader = new InputStreamReader(uri.toURL().openStream(), getEncoding())) { - properties.load(reader); - } + Properties readProperties = applicationIOHelper.readProperties(uri.toURL(), getEncoding()); + properties.putAll(readProperties); +// try (InputStreamReader reader = new InputStreamReader(uri.toURL().openStream(), getEncoding())) { +// properties.load(reader); +// } } /** @@ -2314,9 +2325,10 @@ public class ApplicationConfig { * @since 2.3 */ protected void saveResource(File file, Properties properties, String comment) throws IOException { - try (Writer reader = new OutputStreamWriter(new FileOutputStream(file), getEncoding())) { - properties.store(reader, comment); - } + applicationIOHelper.writeProperties(properties, file, getEncoding(), comment); +// try (Writer reader = new OutputStreamWriter(new FileOutputStream(file), getEncoding())) { +// properties.store(reader, comment); +// } } /** diff --git a/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfigInit.java b/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfigInit.java index cc99d9a..7a627f2 100644 --- a/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfigInit.java +++ b/nuiton-config/src/main/java/org/nuiton/config/ApplicationConfigInit.java @@ -22,6 +22,8 @@ package org.nuiton.config; * #L% */ +import org.nuiton.config.io.ApplicationConfigReadFormat; + import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; @@ -37,6 +39,10 @@ import java.util.Set; */ public class ApplicationConfigInit { + public static ApplicationConfigInit defaultInit() { + return forAllScopes().setReadFormat(ApplicationConfigReadFormat.properties); + } + public static ApplicationConfigInit forAllScopes() { return new ApplicationConfigInit(ApplicationConfigScope.values()); } @@ -56,6 +62,7 @@ public class ApplicationConfigInit { protected String configFilename; protected Properties defaults; protected final Set<ApplicationConfigScope> scopes ; + protected ApplicationConfigReadFormat readFormat; protected ApplicationConfigInit(ApplicationConfigScope...scopes) { this.scopes = Collections.unmodifiableSet(EnumSet.copyOf(Arrays.asList(scopes))); @@ -83,4 +90,12 @@ public class ApplicationConfigInit { return scopes; } + public ApplicationConfigReadFormat getReadFormat() { + return readFormat; + } + + public ApplicationConfigInit setReadFormat(ApplicationConfigReadFormat readFormat) { + this.readFormat = readFormat; + return this; + } } diff --git a/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigIO.java b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigIO.java new file mode 100644 index 0000000..25e9d24 --- /dev/null +++ b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigIO.java @@ -0,0 +1,21 @@ +package org.nuiton.config.io; + +import java.io.File; +import java.net.URL; +import java.util.Properties; + +/** + * Created on 07/10/16. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.1 + */ +public interface ApplicationConfigIO { + + boolean accept(ApplicationConfigReadFormat readFormat); + + Properties readProperties(URL url, String encoding) throws ApplicationConfigReadPropertiesException; + + void writeProperties(Properties properties, File file, String encoding, String comment) throws ApplicationConfigWritePropertiesException; + +} diff --git a/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigReadFormat.java b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigReadFormat.java new file mode 100644 index 0000000..d68d3af --- /dev/null +++ b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigReadFormat.java @@ -0,0 +1,9 @@ +package org.nuiton.config.io; + +/** + * Le format de lecture des ficiers de configuration. + */ +public enum ApplicationConfigReadFormat { + properties, + ini +} diff --git a/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigReadPropertiesException.java b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigReadPropertiesException.java new file mode 100644 index 0000000..113cef8 --- /dev/null +++ b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigReadPropertiesException.java @@ -0,0 +1,17 @@ +package org.nuiton.config.io; + +/** + * Created by tchemit on 07/10/16. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class ApplicationConfigReadPropertiesException extends RuntimeException { + + public ApplicationConfigReadPropertiesException(String message, Throwable cause) { + super(message, cause); + } + + public ApplicationConfigReadPropertiesException(Throwable cause) { + super(cause); + } +} diff --git a/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigWritePropertiesException.java b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigWritePropertiesException.java new file mode 100644 index 0000000..63d4195 --- /dev/null +++ b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationConfigWritePropertiesException.java @@ -0,0 +1,17 @@ +package org.nuiton.config.io; + +/** + * Created by tchemit on 07/10/16. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public class ApplicationConfigWritePropertiesException extends RuntimeException { + + public ApplicationConfigWritePropertiesException(String message, Throwable cause) { + super(message, cause); + } + + public ApplicationConfigWritePropertiesException(Throwable cause) { + super(cause); + } +} diff --git a/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationIOHelper.java b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationIOHelper.java new file mode 100644 index 0000000..f8a8be0 --- /dev/null +++ b/nuiton-config/src/main/java/org/nuiton/config/io/ApplicationIOHelper.java @@ -0,0 +1,49 @@ +package org.nuiton.config.io; + +import com.google.common.base.Preconditions; + +import java.io.File; +import java.net.URL; +import java.util.Properties; +import java.util.ServiceLoader; + +/** + * Created on 07/10/16. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.1 + */ +public class ApplicationIOHelper implements ApplicationConfigIO { + + private final ApplicationConfigIO delegate; + + public ApplicationIOHelper(ApplicationConfigReadFormat readFormat) { + Preconditions.checkNotNull(readFormat, "Can't init with null readFormat"); + ServiceLoader<ApplicationConfigIO> loader = ServiceLoader.load(ApplicationConfigIO.class); + ApplicationConfigIO delegate = null; + for (ApplicationConfigIO applicationConfigIO : loader) { + if (applicationConfigIO.accept(readFormat)) { + delegate = applicationConfigIO; + } + } + Preconditions.checkState(delegate != null, "Could not find ApplicationConfigIO implementation for format: " + readFormat); + this.delegate = delegate; + } + + @Override + public boolean accept(ApplicationConfigReadFormat readFormat) { + // accept all formats + return true; + } + + @Override + public Properties readProperties(URL url, String encoding) throws ApplicationConfigReadPropertiesException { + return delegate.readProperties(url, encoding); + } + + @Override + public void writeProperties(Properties properties, File file, String encoding, String comment) throws ApplicationConfigWritePropertiesException { + delegate.writeProperties(properties, file, encoding, comment); + } + +} -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.