Author: tchemit Date: 2010-04-03 20:38:16 +0200 (Sat, 03 Apr 2010) New Revision: 1815 Log: Anomalie #448: [ApplicationConfig] Make migration of configuration file configurable Modified: trunk/src/main/java/org/nuiton/util/ApplicationConfig.java Modified: trunk/src/main/java/org/nuiton/util/ApplicationConfig.java =================================================================== --- trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-04-03 14:54:19 UTC (rev 1814) +++ trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-04-03 18:38:16 UTC (rev 1815) @@ -23,11 +23,7 @@ import static org.nuiton.i18n.I18n._; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; -import java.io.Writer; +import java.io.*; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -73,7 +69,7 @@ * <h3>Usage</h3> * Create subclass of {@link ApplicationConfig}, where in constructor you call * {@link #setConfigFileName(String)}, {@link #setDefaultOption(String, String)}, - * {@link #addAlias(String, String[])}, {@link #addActionAlias(String, String)}, + * {@link #addAlias(String, String...)}, {@link #addActionAlias(String, String)}, * to have properly value. * <pre> * conf = new MonAppConfig(); @@ -94,7 +90,7 @@ * <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} sauvegarde les donnees dans /etc * <li> {@link #saveForUser} sauvegarde les donnees dans $HOME * </ul> @@ -265,6 +261,7 @@ /** Configuration file key option. */ static final public String CONFIG_FILE_NAME = "config.file"; + /** TODO */ static final public String APP_NAME = "app.name"; /** @@ -282,7 +279,8 @@ /** System os name. (windows, linux, max os x) */ protected String osName; - protected boolean useOnlyAliases = false; + /** TODO */ + protected boolean useOnlyAliases; /** * file $user.home/.[filename] @@ -294,25 +292,48 @@ protected String userPath = getUserHome() + File.separator + "."; /** vrai si on est en train de parser les options de la ligne de commande. */ - protected boolean inParseOptionPhase = false; + 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); + + /** 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>>(); /** suport of config modification. */ @@ -324,7 +345,7 @@ * * @since 1.0.0-rc-9 */ - static public interface OptionDef { + public interface OptionDef { /** * @return la clef identifiant l'option @@ -360,11 +381,12 @@ boolean isFinal(); } + /** TODO */ static public class Action { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) - static public @interface Step { + public @interface Step { int value() default 0; } @@ -380,7 +402,10 @@ this.params = params; } - public void doAction() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException { + public void doAction() throws IllegalAccessException, + IllegalArgumentException, + InvocationTargetException, + InstantiationException { ObjectUtil.call(o, m, params); } } @@ -410,7 +435,7 @@ * @see ConverterUtil#initConverters() */ public ApplicationConfig() { - setConfigFileName(this.getClass().getSimpleName()); + setConfigFileName(getClass().getSimpleName()); // init extra-converters ConverterUtil.initConverters(); @@ -462,7 +487,9 @@ * @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 { + public void save(File file, + boolean forceAll, + String... excludeKeys) throws IOException { // store sorted in file Properties prop = new SortedProperties(); @@ -485,15 +512,12 @@ prop.remove(excludeKey); } - Writer writer = null; + Writer writer = new FileWriter(file); try { - writer = new FileWriter(file); prop.store(writer, "Last saved " + new java.util.Date()); } finally { - if (writer != null) { - writer.close(); - } + writer.close(); } } @@ -509,7 +533,8 @@ save(file, false, excludeKeys); } catch (IOException eee) { if (log.isWarnEnabled()) { - log.warn(_("nuitonutil.error.applicationconfig.save", file), eee); + log.warn(_("nuitonutil.error.applicationconfig.save", file), + eee); } } } @@ -526,7 +551,8 @@ save(file, false, excludeKeys); } catch (IOException eee) { if (log.isWarnEnabled()) { - log.warn(_("nuitonutil.error.applicationconfig.save", file), eee); + log.warn(_("nuitonutil.error.applicationconfig.save", file), + eee); } } } @@ -550,7 +576,7 @@ Integer step = action.step; List<Action> list = actions.get(step); if (list == null) { - list = new LinkedList<ApplicationConfig.Action>(); + list = new LinkedList<Action>(); actions.put(step, list); } list.add(action); @@ -562,14 +588,17 @@ * * @param step do action only defined in this step * - * @throws IllegalAccessException - * @throws IllegalArgumentException - * @throws InvocationTargetException - * @throws InstantiationException + * @throws IllegalAccessException TODO + * @throws IllegalArgumentException TODO + * @throws InvocationTargetException TODO + * @throws InstantiationException TODO * * @see Action.Step */ - public void doAction(int step) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException { + public void doAction(int step) throws IllegalAccessException, + IllegalArgumentException, + InvocationTargetException, + InstantiationException { List<Action> list = actions.get(step); if (list != null) { for (Action a : list) { @@ -598,10 +627,11 @@ /** * Add alias for action. This method put just -- front the actionMethod and - * call {@link #addAlias(String, String[])} + * 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 + * @param actionMethod must be fully qualified method path: + * package.Class.method */ public void addActionAlias(String alias, String actionMethod) { addAlias(alias, "--" + actionMethod); @@ -641,6 +671,7 @@ * pollen.config.file * * @param appName to use as application context + * @since 1.2.1 */ public void setAppName(String appName) { setDefaultOption(APP_NAME, appName); @@ -669,7 +700,9 @@ if (result == null) { result = getSystemConfigurationPath(); } - + if (log.isDebugEnabled()) { + log.debug(result); + } return result; } @@ -683,6 +716,7 @@ * </ul> * * @since 1.2.1 + * @return TODO */ protected String getSystemConfigurationPath() { @@ -726,7 +760,9 @@ // look for in /etc/ systemPath = File.separator + "etc" + File.separator; } - + if (log.isDebugEnabled()) { + log.debug(systemPath); + } return systemPath; } @@ -744,6 +780,7 @@ * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html * * @since 1.2.1 + * @return TODO */ protected String getUserPath() { @@ -760,7 +797,7 @@ if (osName.toLowerCase().contains("windows")) { try { String appDataEV = System.getenv("APPDATA"); - if ((appDataEV != null) && (appDataEV.length() > 0)) { + if (appDataEV != null && appDataEV.length() > 0) { userPath = appDataEV; } } catch (SecurityException ignore) { @@ -772,7 +809,8 @@ } } else if (osName.toLowerCase().contains("mac os x")) { // ${userHome}/Library/Application Support/${applicationId} - userPath = userHome + File.separator + "/Library/Application Support"; + userPath = userHome + File.separator + + "/Library/Application Support"; } else { // ${userHome}/.config/ userPath = userHome + "/.config"; @@ -842,7 +880,8 @@ // Ex : getProperty("myName"); if (value != null) { // Ex : value="Thimel" - result = result.substring(0, pos) + value + result.substring(posEnd + 1); + 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 @@ -897,7 +936,6 @@ * @return typed value */ public <T> T getOption(Class<T> clazz, String key) { - T result = null; String cacheKey = key + "-" + clazz.getName(); String value = getOption(key); @@ -905,6 +943,7 @@ if (value != null) { hash = value.hashCode(); } + T result; CacheItem<T> cacheItem = (CacheItem<T>) cacheOption.get(cacheKey); // compute value if value don't exist in cacheOption or // if it's modified since last computation @@ -1027,7 +1066,7 @@ * @return Properties which contains all options */ public Properties getOptions() { - return this.options; + return options; } /** @@ -1048,7 +1087,7 @@ */ protected Map<String, Method> getMethods() { // looking for all methods set on ApplicationConfig - Method[] allMethods = this.getClass().getMethods(); + Method[] allMethods = getClass().getMethods(); Map<String, Method> methods = new HashMap<String, Method>(); for (Method m : allMethods) { String methodName = m.getName(); @@ -1098,15 +1137,21 @@ * if package, class or method missing, default is used * * @param name name of the action - * @param args + * @param args TODO * @return the created action - * @throws ArgumentsParserException - * @throws IllegalAccessException - * @throws IllegalArgumentException - * @throws InstantiationException - * @throws java.lang.reflect.InvocationTargetException + * @throws ArgumentsParserException TODO + * @throws IllegalAccessException TODO + * @throws IllegalArgumentException TODO + * @throws InstantiationException TODO + * @throws InvocationTargetException TODO */ - protected Action createAction(String name, ListIterator<String> args) throws ArgumentsParserException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + protected Action createAction(String name, + ListIterator<String> args) + throws ArgumentsParserException, + InstantiationException, + IllegalAccessException, + IllegalArgumentException, + InvocationTargetException { Action result = null; Class<?> clazz; @@ -1136,13 +1181,15 @@ if (methods.size() > 0) { if (methods.size() > 1) { log.warn(String.format( - "More than one method found, used the first: %s", methods)); + "More than one method found, used the first: %s", + methods)); } method = methods.get(0); } if (method != null) { - args.remove(); // remove option from command line, because is used now + // 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); @@ -1151,7 +1198,8 @@ o = ConstructorUtils.invokeConstructor(clazz, this); } catch (NoSuchMethodException eee) { log.debug(String.format( - "Use default constructor, because no constructor with Config parameter on class %s", + "Use default constructor, because no constructor" + + " with Config parameter on class %s", clazz.getName())); o = clazz.newInstance(); } @@ -1177,7 +1225,7 @@ * Load configuration file and prepare Action. * * @param args argument as main(String[] args) - * @throws ArgumentsParserException + * @throws ArgumentsParserException TODO */ public void parse(String[] args) throws ArgumentsParserException { try { @@ -1194,7 +1242,8 @@ // first parse option inParseOptionPhase = true; - for (ListIterator<String> i = arguments.listIterator(); i.hasNext();) { + for (ListIterator<String> i = arguments.listIterator(); + i.hasNext();) { String arg = i.next(); if (arg.equals("--")) { // stop parsing @@ -1207,7 +1256,9 @@ 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))); + log.debug(String.format( + "Set option '%s' with method '%s %s'", + optionName, m, Arrays.toString(params))); } ObjectUtil.call(this, m, params); } @@ -1225,19 +1276,28 @@ // classpath String filename = getConfigFileName(); - URL inClasspath = ClassLoader.getSystemClassLoader().getResource(filename); + URL inClasspath = + ClassLoader.getSystemClassLoader().getResource(filename); if (inClasspath == null) { - inClasspath = ApplicationConfig.class.getResource("/" + filename); + inClasspath = ApplicationConfig.class.getResource("/" + + filename); } if (inClasspath != null) { if (log.isInfoEnabled()) { - log.info("Chargement du fichier de config (classpath) : " + inClasspath); + log.info("Loading configuration file (classpath) : " + + inClasspath); } - classpath.load(inClasspath.openStream()); + InputStream stream = inClasspath.openStream(); + try { + classpath.load(stream); + } finally { + stream.close(); + } } else { if (log.isDebugEnabled()) { - log.debug("No configuration file found in classpath : /" + filename); + log.debug("No configuration file found in classpath : /" + + filename); } } @@ -1245,39 +1305,49 @@ File etcConfig = new File(getConfigPath(), filename); if (etcConfig.exists()) { if (log.isInfoEnabled()) { - log.info("Chargement du fichier de config (etc) : " + etcConfig); + log.info("Loading configuration file (etc) : " + etcConfig); } - etcfile.load(etcConfig.toURI().toURL().openStream()); + InputStream stream = etcConfig.toURI().toURL().openStream(); + try { + etcfile.load(stream); + } finally { + stream.close(); + } } else { if (log.isDebugEnabled()) { - log.debug("No configuration file found in system : " + etcConfig.getAbsolutePath()); + log.debug("No configuration file found in system : " + + etcConfig.getAbsolutePath()); } } // user home directory File homeConfig = new File(getUserPath(), filename); - File oldHomeConfig = new File(userPath + filename); // don't use new File(String, String) + // don't use new File(String, String) + File oldHomeConfig = new File(userPath + filename); // migration, if homeConfig doesn't exists and oldHomeConfig does if (!homeConfig.exists() && oldHomeConfig.exists()) { - if (log.isInfoEnabled()) { - log.info(_("Moving old configuration file from %s to %s", oldHomeConfig.getPath(), homeConfig.getPath())); - } - - oldHomeConfig.renameTo(homeConfig); + migrateUserConfigurationFile(oldHomeConfig, homeConfig); } // end of migration if (homeConfig.exists()) { if (log.isInfoEnabled()) { - log.info("Chargement du fichier de config (home) : " + homeConfig); + log.info("Loading configuration file (home) : " + + homeConfig); } - homefile.load(homeConfig.toURI().toURL().openStream()); + InputStream stream = homeConfig.toURI().toURL().openStream(); + try { + homefile.load(stream); + } finally { + stream.close(); + } } else { if (log.isDebugEnabled()) { - log.debug("No configuration file found in user home : " + homeConfig.getAbsolutePath()); + log.debug("No configuration file found in user home : " + + homeConfig.getAbsolutePath()); } } @@ -1285,20 +1355,27 @@ File config = new File(filename); if (config.exists()) { if (log.isInfoEnabled()) { - log.info("Chargement du fichier de config (curr) : " + config); + log.info("Loading configuration file (curr) : " + config); } - curfile.load(config.toURI().toURL().openStream()); + InputStream stream = config.toURI().toURL().openStream(); + try { + curfile.load(stream); + } finally { + stream.close(); + } } else { if (log.isDebugEnabled()) { - log.debug("No configuration file found in current directory : " + config.getAbsolutePath()); + 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();) { + for (ListIterator<String> i = arguments.listIterator(); + i.hasNext();) { String arg = i.next(); if (arg.equals("--")) { // stop parsing @@ -1318,12 +1395,42 @@ unparsed.addAll(arguments); } catch (Exception eee) { - eee.printStackTrace(); + if (log.isErrorEnabled()) { + log.error(eee); + } throw new ArgumentsParserException("Can't parse argument", eee); } } /** + * 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(_("Moving old configuration file from %s to %s", + 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); + } + } + + /** * For debugging. */ public void printConfig() { @@ -1350,7 +1457,8 @@ output.println("options " + options); } - protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + protected void firePropertyChange(String propertyName, + Object oldValue, Object newValue) { pcs.firePropertyChange(propertyName, oldValue, newValue); } @@ -1358,7 +1466,8 @@ pcs.addPropertyChangeListener(listener); } - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) { pcs.addPropertyChangeListener(propertyName, listener); } @@ -1366,7 +1475,8 @@ pcs.removePropertyChangeListener(listener); } - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) { pcs.removePropertyChangeListener(propertyName, listener); } @@ -1374,7 +1484,8 @@ return pcs.hasListeners(propertyName); } - public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + public synchronized PropertyChangeListener[] getPropertyChangeListeners( + String propertyName) { return pcs.getPropertyChangeListeners(propertyName); }
participants (1)
-
tchemit@users.nuiton.org