Author: tchemit Date: 2012-05-01 14:49:55 +0200 (Tue, 01 May 2012) New Revision: 2328 Url: http://nuiton.org/repositories/revision/nuiton-utils/2328 Log: fixes #2073: Improve ApplicationConfig code Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java =================================================================== --- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java 2012-05-01 12:46:41 UTC (rev 2327) +++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfig.java 2012-05-01 12:49:55 UTC (rev 2328) @@ -28,6 +28,7 @@ import org.apache.commons.beanutils.ConstructorUtils; import org.apache.commons.collections.EnumerationUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.util.converter.ConverterUtil; @@ -75,7 +76,7 @@ /** * Application configuration. - * + * <p/> * <h3>A finir...</h3> * <ul> * <li>Ajout d'annotations sur les methodes @@ -91,11 +92,11 @@ * 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> * * static public ApplicationConfig getConfig( @@ -116,36 +117,36 @@ * } * * </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 #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 @@ -161,14 +162,14 @@ * <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 @@ -177,15 +178,15 @@ * 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 @@ -222,7 +223,7 @@ * </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 @@ -234,7 +235,7 @@ * 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 @@ -257,7 +258,7 @@ * 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: @@ -273,10 +274,10 @@ * <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. @@ -288,48 +289,50 @@ * fullname = ${firstname} ${lastname} * </pre> * <tt>getOption("fullname")</tt> retournera <tt>"John Doe"</tt>. - * - * @since 0.30 + * * @author poussin * @version $Revision$ - * <p/> - * Last update $Date$ by */ + * <p/> + * Last update $Date$ by + * @since 0.30 + */ public class ApplicationConfig { /** Logger. */ static private Log log = LogFactory.getLog(ApplicationConfig.class); /** Used to know what is separator between class and method on command line. */ - static final private String CLASS_METHOD_SEPARATOR = "#"; - static final public String LIST_SEPARATOR = ","; + private static final String CLASS_METHOD_SEPARATOR = "#"; + public static final String LIST_SEPARATOR = ","; + /** Configuration file key option. */ - static final public String CONFIG_FILE_NAME = "config.file"; + public static final String CONFIG_FILE_NAME = "config.file"; /** Configuration encoding key option. */ - static final public String CONFIG_ENCODING = "config.encoding"; + 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}. */ - static final public String APP_NAME = "app.name"; + /** 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 */ - static final public String ADJUSTING_PROPERTY = "adjusting"; + 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> + * <li>Linux : /etc/xxx.properties + * <li>Windows : C:\\Windows\\System32\\xxx.properties + * <li>Mac OS : /etc/ + * </ul> */ - static final public String CONFIG_PATH = "config.path"; + public static final String CONFIG_PATH = "config.path"; /** System os name. (windows, linux, max os x) */ protected String osName; @@ -339,8 +342,9 @@ /** * file $user.home/.[filename] - * + * <p/> * Not used anymore. Just used for migration issue. + * * @deprecated since 1.2.1, and can't be removed (for migration purpose) */ @Deprecated @@ -401,9 +405,9 @@ * 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 - * @see #saveUserAction */ private boolean adjusting; @@ -415,8 +419,9 @@ /** * Init ApplicationConfig with current simple class name as config file. - * + * <p/> * Also init converters. + * * @see ConverterUtil#initConverters() */ public ApplicationConfig() { @@ -431,46 +436,36 @@ } /** - * Create WikittyConfig and load particular configuration filename - * + * Create configuration for a particular configuration filename + * * @param configFilename name of config to use */ public ApplicationConfig(String configFilename) { - this(null, null, null, 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(null, null, defaults, null); + this(defaults, null); } - + /** - * All in one, this constructor allow to pass all necessary argument to + * 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 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 <O extends OptionDef, A extends ActionDef> ApplicationConfig( - Class<O> optionClass, Class<A> actionClass, - Properties defaults, String configFilename) { - this(); - if (optionClass != null) { - loadDefaultOptions(optionClass); - } - if (actionClass != null) { - loadActions(actionClass); - } - + public ApplicationConfig(Properties defaults, String configFilename) { if (defaults != null) { // iterate with Properties method and not with Hashtable method to // prevent missed value with chained Properties object @@ -478,15 +473,39 @@ setDefaultOption(key, defaults.getProperty(key)); } } - + if (configFilename != null) { setDefaultOption(CONFIG_FILE_NAME, configFilename); } - + } - + /** + * 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() { @@ -496,6 +515,7 @@ /** * Get user name (system property {@code user.name}). + * * @return user name */ public String getUsername() { @@ -507,12 +527,26 @@ * 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} + * @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 : optionClass.getEnumConstants()) { + for (OptionDef o : options) { if (o.getDefaultValue() != null) { setDefaultOption(o.getKey(), o.getDefaultValue()); } @@ -523,12 +557,26 @@ * Load actions of enum pass in param (enum must extend {@link ActionDef}) * * @param actionClass to load - * @param <A> type of enum extend {@link ActionDef} + * @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 : actionClass.getEnumConstants()) { + for (A a : actions) { for (String alias : a.getAliases()) { addActionAlias(alias, a.getAction()); } @@ -549,9 +597,9 @@ /** * 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 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 */ @@ -637,7 +685,7 @@ * @return the system config file location */ public File getSystemConfigFile() { - File file = new File(getConfigPath(), getConfigFileName()); + File file = new File(getConfigPath(), getConfigFileName()); return file; } @@ -680,8 +728,8 @@ * Return ordered action step number. * example: 0,1,5,6 * + * @return ordered action step number * @since 2.4 - * @return ordered action step number */ public List<Integer> getActionStep() { List<Integer> result = new ArrayList<Integer>(actions.keySet()); @@ -692,18 +740,17 @@ /** * Do all action in specified order step (first 0). * - * @throws IllegalAccessException if action invocation failed - * @throws IllegalArgumentException if action invocation failed + * @throws IllegalAccessException if action invocation failed + * @throws IllegalArgumentException if action invocation failed * @throws InvocationTargetException if action invocation failed - * @throws InstantiationException if action invocation failed - * + * @throws InstantiationException if action invocation failed * @see Action.Step * @since 2.4 */ public void doAllAction() throws IllegalAccessException, - IllegalArgumentException, - InvocationTargetException, - InstantiationException { + IllegalArgumentException, + InvocationTargetException, + InstantiationException { for (int step : getActionStep()) { doAction(step); } @@ -711,20 +758,18 @@ /** * 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 IllegalAccessException if action invocation failed + * @throws IllegalArgumentException if action invocation failed * @throws InvocationTargetException if action invocation failed - * @throws InstantiationException if action invocation failed - * + * @throws InstantiationException if action invocation failed * @see Action.Step */ public void doAction(int step) throws IllegalAccessException, - IllegalArgumentException, - InvocationTargetException, - InstantiationException { + IllegalArgumentException, + InvocationTargetException, + InstantiationException { List<Action> list = actions.get(step); if (list != null) { for (Action a : list) { @@ -743,7 +788,7 @@ /** * Get the encoding used to read/write resources. - * + * <p/> * This value is stored as an option using the * {@link #getEncodingOption()} key. * @@ -761,7 +806,7 @@ * @since 2.3 */ public void setEncoding(String encoding) { - setDefaultOption(getEncodingOption(),encoding); + setDefaultOption(getEncodingOption(), encoding); } /** @@ -841,10 +886,10 @@ /** * 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} + * {@code pollen.config.path} * * @param appName to use as application context * @since 1.2.1 @@ -855,21 +900,21 @@ /** * 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 + * <li>{@link #CONFIG_PATH} option + * <li>system dependant path * </ul> - * + * + * @return path to use with endind {@link File#separator} * @since 1.2.1 - * @return path to use with endind {@link File#separator} */ public String getConfigPath() { // Concat appName to configPath option to specify context for // application deployment String appName = getOption(APP_NAME) != null ? - getOption(APP_NAME) + "." : ""; + getOption(APP_NAME) + "." : ""; String result = getOption(appName + CONFIG_PATH); @@ -884,15 +929,15 @@ /** * Get system configuration path. - * + * <p/> * Currently supported: * <ul> - * <li>Windows : C:\Windows\System32 - * <li>Unix : /etc/ + * <li>Windows : C:\Windows\System32 + * <li>Unix : /etc/ * </ul> - * + * + * @return the system path * @since 1.2.1 - * @return the system path */ protected String getSystemConfigurationPath() { @@ -929,7 +974,7 @@ // default value systemPath = "C:\\Windows\\System32"; } - + // %SystemDrive% exists too : C: } else { // All others are unix like @@ -944,22 +989,22 @@ /** * 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 + * <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 - * @return the user configuration path */ public String getUserConfigDirectory() { - + String userPath = null; String userHome = null; @@ -967,7 +1012,7 @@ userHome = getUserHome(); } catch (SecurityException ignore) { } - + if (userHome != null) { // windows if (osName.toLowerCase().contains("windows")) { @@ -992,7 +1037,7 @@ userPath = userHome + "/.config"; } } - + // what if null ? return userPath; @@ -1000,6 +1045,7 @@ /** * Retourne si un option existe ou non + * * @param key * @return */ @@ -1012,6 +1058,7 @@ /** * Retourne si un option existe ou non + * * @param key * @return */ @@ -1022,6 +1069,7 @@ /** * ajoute un objet dans le context, la classe de l'objet est utilise comme cle + * * @since 2.4.2 */ public void putObject(Object o) { @@ -1030,6 +1078,7 @@ /** * ajoute un objet dans le context, 'name' est utilise comme cle + * * @since 2.4.2 */ public void putObject(String name, Object o) { @@ -1039,9 +1088,9 @@ /** * 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 * - * E peut prendre en argument du contruteur un objet de type ApplicationConfig - * * @since 2.4.2 */ public <E> E getObject(Class<E> clazz) { @@ -1053,9 +1102,9 @@ * 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 * - * 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) { @@ -1072,6 +1121,7 @@ * 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) { @@ -1088,7 +1138,7 @@ * 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 @@ -1102,7 +1152,7 @@ * 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 @@ -1120,9 +1170,9 @@ * 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 * - * La classe peut avoir un constructeur prenant un ApplicationConfig - * * @since 2.4.2 */ public <E> E getOptionAsSingleton(Class<E> clazz, String key) { @@ -1146,7 +1196,7 @@ /** * get option value as string. - * + * <p/> * Replace inner ${xxx} value. * * @param key the option's key @@ -1161,7 +1211,7 @@ /** * Replace included ${xxx} suboptions by their values. - * + * * @param option option to replace into * @return replaced option * @since 1.1.3 @@ -1208,9 +1258,9 @@ /** * 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 + * @return la liste des options filtrées */ public Properties getOptionStartsWith(String prefix) { Properties result = new Properties(); @@ -1228,7 +1278,7 @@ * Get option value from a option definition. * * @param key the definition of the option - * @return the value for the given option + * @return the value for the given option */ public Object getOption(OptionDef key) { Object result = getOption(key.getType(), key.getKey()); @@ -1238,7 +1288,7 @@ /** * Get option value as typed value. * - * @param <T> type of the object wanted as return type + * @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 @@ -1255,16 +1305,16 @@ /** * 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 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 */ @@ -1312,7 +1362,7 @@ /** * 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 */ @@ -1338,8 +1388,8 @@ /** * Get option value as {@link Properties}, this property must be a filepath - * and file must be a properties. - * + * and file must be a properties. + * <p/> * Returned Properties is {@link RecursiveProperties}. * * @param key the option's key @@ -1421,7 +1471,7 @@ */ public int getOptionAsInt(String key) { Integer result = getOption(Integer.class, key); - if (result==null) { + if (result == null) { // primitive value can not be null result = 0; } @@ -1443,12 +1493,12 @@ return result; } - /** + /** * Get option value as {@code float}. * * @param key the option's key * @return value as {@code float} - * @since 2.2 + * @since 2.2 */ public float getOptionAsFloat(String key) { Float result = getOption(Float.class, key); @@ -1516,7 +1566,7 @@ /** * Get all options from configuration. - * + * * @return Properties which contains all options */ public Properties getOptions() { @@ -1535,7 +1585,7 @@ /** * Get all options as flat {@link Properties} object (replace inner options). - * + * * @return flat Properties object * @since 1.2.2 */ @@ -1545,7 +1595,7 @@ /** * 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 @@ -1557,8 +1607,7 @@ if (replaceInner) { // replace ${xxx} option propertyValue = getOption(propertyKey); - } - else { + } else { // do not replace ${xxx} option propertyValue = options.getProperty(propertyKey); } @@ -1569,7 +1618,7 @@ /** * Install the {@link #saveUserAction} on givne {@code properties}. - * + * * @param properties properties on which insalls the saveUserAction */ protected void installSaveUserAction(String... properties) { @@ -1594,7 +1643,7 @@ setAdjusting(false); } } - + /** * Get all set method on this object or super object. * @@ -1655,19 +1704,19 @@ * @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 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 { + InstantiationException, + IllegalAccessException, + IllegalArgumentException, + InvocationTargetException { Action result = null; Class<?> clazz; @@ -1746,7 +1795,7 @@ */ public ApplicationConfig parse(String... args) throws ArgumentsParserException { if (args == null) { - args = ArrayUtil.EMPTY_STRING_ARRAY; + args = ArrayUtils.EMPTY_STRING_ARRAY; } try { Map<String, Method> methods = getMethods(); @@ -1763,7 +1812,7 @@ // first parse option inParseOptionPhase = true; for (ListIterator<String> i = arguments.listIterator(); - i.hasNext();) { + i.hasNext(); ) { String arg = i.next(); if (arg.equals("--")) { // stop parsing @@ -1775,7 +1824,7 @@ i.remove(); // remove this arg because is used now Method m = methods.get(optionName); String[] params = getParams(m, i); - if (log.isDebugEnabled()) { + if (log.isDebugEnabled()) { log.debug(String.format( "Set option '%s' with method '%s %s'", optionName, m, Arrays.toString(params))); @@ -1827,11 +1876,10 @@ // File etcConfig = new File(getConfigPath(), filename); if (etcConfig.exists()) { if (log.isInfoEnabled()) { - log.info("Loading configuration file (etc) : " + etcConfig); + log.info("Loading configuration file (etc) : " + etcConfig); } loadResource(etcConfig.toURI(), etcfile); - } - else { + } else { if (log.isDebugEnabled()) { log.debug("No configuration file found in system : " + etcConfig.getAbsolutePath()); @@ -1859,8 +1907,7 @@ homeConfig); } loadResource(homeConfig.toURI(), homefile); - } - else { + } else { if (log.isDebugEnabled()) { log.debug("No configuration file found in user home : " + homeConfig.getAbsolutePath()); @@ -1874,8 +1921,7 @@ log.info("Loading configuration file (curr) : " + config); } loadResource(config.toURI(), curfile); - } - else { + } else { if (log.isDebugEnabled()) { log.debug("No configuration file found in current" + " directory : " + config.getAbsolutePath()); @@ -1886,7 +1932,7 @@ // third parse action and do action // for (ListIterator<String> i = arguments.listIterator(); - i.hasNext();) { + i.hasNext(); ) { String arg = i.next(); if (arg.equals("--")) { // stop parsing @@ -1946,11 +1992,11 @@ * Load a resources given by his {@code uri} to the given * {@code properties} argument. * - * @param uri the uri to load + * @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 - * @see Properties#load(Reader) */ protected void loadResource(URI uri, Properties properties) throws IOException { InputStreamReader reader = @@ -1966,12 +2012,12 @@ * 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 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 + * @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 - * @see Properties#store(Writer, String) */ protected void saveResource(File file, Properties properties, @@ -1985,9 +2031,7 @@ } } - /** - * For debugging. - */ + /** For debugging. */ public void printConfig() { System.out.println("-------------------Value-------------------------"); printConfig(System.out); @@ -1996,7 +2040,7 @@ /** * Print out current configuration in specified output. - * + * * @param output output to write config to * @since 1.1.4 */ @@ -2016,7 +2060,7 @@ * 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 + * @param padding for better presentation, you can use padding to align '=' sign * @return string that represent config * @since 1.5.2 */ @@ -2024,7 +2068,7 @@ String msg = "Configuration:\n"; for (String key : getFlatOptions().stringPropertyNames()) { if (includePattern == null || "".equals(includePattern) - || key.matches(includePattern)) { + || key.matches(includePattern)) { String value = getOption(key); msg += String.format("\t%" + padding + "s = %s\n", key, value); } @@ -2067,22 +2111,21 @@ 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/> + * <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}. * - * <b>Note:</b> Will not save if {@link #isAdjusting()} is {@code true}. - * * @since 1.3 */ private final PropertyChangeListener saveUserAction = @@ -2108,7 +2151,7 @@ /** * Le contrat de marquage des options, on utilise cette interface pour * caracteriser une option de configuration. - * + * <p/> * <pre> * public enum MyConfigOption implements OptionDef { * @@ -2192,36 +2235,30 @@ */ public interface OptionDef extends Serializable { - /** - * @return la clef identifiant l'option - */ + /** @return la clef identifiant l'option */ String getKey(); - /** - * @return le type de l'option - */ + /** @return le type de l'option */ Class<?> getType(); - /** - * @return la clef i18n de description de l'option - */ + /** @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 + * caracteres */ String getDefaultValue(); /** * @return <code>true</code> si l'option ne peut etre sauvegardee sur - * disque (utile par exemple pour les mots de passe, ...) + * 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, ...) + * par exemple pour la version de l'application, ...) */ boolean isFinal(); @@ -2250,9 +2287,9 @@ /** * 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"); @@ -2311,9 +2348,13 @@ 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) { @@ -2324,9 +2365,9 @@ } public void doAction() throws IllegalAccessException, - IllegalArgumentException, - InvocationTargetException, - InstantiationException { + IllegalArgumentException, + InvocationTargetException, + InstantiationException { ObjectUtil.call(o, m, params); } } @@ -2340,6 +2381,7 @@ /** typed option value */ public T item; + /** hash of string representation */ public int hash; @@ -2352,7 +2394,9 @@ static public class OptionList { protected ApplicationConfig config; + protected String key; + protected String value; public OptionList(ApplicationConfig config, String key, String value) { @@ -2362,12 +2406,13 @@ } protected <T> List<T> convertListOption(Class<T> type) { - List<T> result= (List<T>) config.convertOption(type, key, - value, - true + List<T> result = (List<T>) config.convertOption(type, key, + value, + true ); return result; } + /** * Get option value as {@link String}. * Added: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java =================================================================== --- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java (rev 0) +++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java 2012-05-01 12:49:55 UTC (rev 2328) @@ -0,0 +1,117 @@ +/* + * #%L + * Nuiton Utils :: Nuiton Utils + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2012 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.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@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; + } +} Property changes on: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationConfigHelper.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native