Index: lutinutil/src/java/org/codelutin/option/Config.java diff -u lutinutil/src/java/org/codelutin/option/Config.java:1.2 lutinutil/src/java/org/codelutin/option/Config.java:1.3 --- lutinutil/src/java/org/codelutin/option/Config.java:1.2 Tue Jan 1 17:26:18 2008 +++ lutinutil/src/java/org/codelutin/option/Config.java Thu Jan 3 06:06:25 2008 @@ -18,7 +18,6 @@ * ##% */ package org.codelutin.option; -import org.apache.commons.beanutils.ConvertUtils; import static org.codelutin.i18n.I18n._; import org.codelutin.util.ReflectUtil; @@ -29,6 +28,7 @@ import java.net.URI; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; @@ -84,12 +84,15 @@ * @author chemit */ public abstract class Config { - /** * la méthode à implanter pour initialiser la config (positionnement la source * par exemple) + * + * @throws Exception if any problem while init */ - protected abstract void init(); + protected abstract void init() throws Exception; + + public abstract void save() throws Exception; /** la catégorie de la config (clef unique non typée) */ protected final String category; @@ -100,9 +103,6 @@ /** la liste des clefs actuellement utilisées dans la configuration */ protected final List safeKeys; - /** les valeurs des propriétés de la configuration, indexées par leur clef typée */ - protected Map data; - /** the internal map of rejected data indexed by their key found */ protected SortedMap unsafeData; @@ -112,21 +112,28 @@ /** la source utilisée pour les opérations IO de la config */ protected URI source; + protected final boolean initDone; + protected Config(String category) { this.category = category; universe = Collections.unmodifiableList(ReflectUtil.getConstants(getClass(), ConfigPropertyKey.class)); safeKeys = new ArrayList(); - init(); + try { + init(); + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + initDone = true; + } } /** * @param key la clef typée de la propriété recherchée * @return la valeur de la propriété, ou la valeur par défaut si non trouvée */ - @SuppressWarnings({"unchecked"}) public T getProperty(ConfigPropertyKey key) { if (safeKeys.contains(key)) { - return (T) getData().get(key); + return key.getCurrentValue(); } if (universe.contains(key)) { // try default value @@ -135,6 +142,16 @@ return null; } + @SuppressWarnings({"unchecked"}) + public ConfigPropertyKey getPropertyKey(String key) { + for (ConfigPropertyKey configPropertyKey : universe) { + if (configPropertyKey.getKey().equalsIgnoreCase(key)) { + return (ConfigPropertyKey) configPropertyKey; + } + } + return null; + } + /** @return l'univers de clefs de propriétés connues dans cette config. */ public List getUniverse() { return universe; @@ -155,6 +172,11 @@ return safeKeys.isEmpty(); } + /** @return true si au moins une propriété est modifiée. */ + public boolean isModified() { + return !isEmpty() && !getModifiedKeys().isEmpty(); + } + /** @return true si aucune propriété non sûre n'est présente. */ public boolean isSafe() { return unsafeData == null || unsafeData.isEmpty(); @@ -209,6 +231,22 @@ return result; } + public List getModifiedKeys() { + List result = new ArrayList(); + for (ConfigPropertyKey o : safeKeys) { + if (o.isModified()) { + result.add(o); + } + } + return result; + } + + public List getUnModifiedKeys() { + List result = new ArrayList(safeKeys); + result.removeAll(getModifiedKeys()); + return result; + } + /** * Remove a unsafe property using a given unsage key, if there is a such * unsafe property. @@ -216,10 +254,9 @@ * @param key the key to use */ public void removeUnsafeData(Object key) { - if (isSafe()) { - return; + if (!isSafe()) { + getUnsafeData().remove(key); } - getUnsafeData().remove(key); } /** @@ -229,14 +266,11 @@ * always true. */ public void clear() { - if (data != null) { - data.clear(); - } if (tmp != null) { tmp.clear(); } + clearSafeData(true); clearUnsafeData(); - safeKeys.clear(); } /** @@ -252,6 +286,23 @@ } /** + * clear the instance safeData. + *

+ * After the method invocation, the {@link #isEmpty()}'s method's return is + * always b. + * + * @param b flag to says, remove safeKey + */ + public void clearSafeData(boolean b) { + for (Iterator it = safeKeys.iterator(); it.hasNext();) + { + ConfigPropertyKey safeKey = it.next(); + safeKey.clear(b); + it.remove(); + } + } + + /** * Fill a {@link Properties} object with all safe properties convert to String * (should be used to store the config with Properties.store method) * @@ -260,8 +311,8 @@ public Properties toProperties() { Properties result = new Properties(); if (!isEmpty()) { - for (ConfigPropertyKey key : getSafeKeys()) { - Object val = getData().get(key); + for (ConfigPropertyKey key : getSafeKeys()) { + Object val = key.getCurrentValue(); // always convert the value to String result.put(key.getKey(), val == null ? "" : val.toString()); } @@ -366,8 +417,8 @@ getTmp().clear(); try { if (!isEmpty()) { - for (ConfigPropertyKey key : getSafeKeys()) { - Object val = data.get(key); + for (ConfigPropertyKey key : getSafeKeys()) { + Object val = key.getCurrentValue(); // a shame that Properties.store can only deal with String value getTmp().put(key.getKey(), val == null ? "" : val.toString()); } @@ -378,17 +429,50 @@ } } + /** + * Set the value for a given property using his def. + * + * @param def the given key to use + * @param value the given valuer to set + */ + public void setProperty(ConfigPropertyKey def, Object value) { + checkAuthorizedKey(def); + if (initDone && def.isFinal()) { + // fatal error , final property + throw new IllegalArgumentException(_("can not modify a final configuration [{0}] property {1}", category, def)); + } + if (value == null) { + removeProperty(def); + return; + } + + Class klass = def.getType(); + + if (klass == String.class || value.getClass() == String.class || value.getClass() == klass) { + T typeValue = def.convert(klass, value); + if (typeValue != null) { + addProperty(def, typeValue); + } + return; + } + addUnsafeData(def.getKey(), value); + } @Override public String toString() { - StringBuilder s = new StringBuilder(super.toString()).append("'); if (!isEmpty()) { + List propertyKeys; + propertyKeys = getModifiedKeys(); + if (!propertyKeys.isEmpty()) { + s.append(" (").append(propertyKeys.size()).append(" modified) "); + } for (ConfigPropertyKey key : safeKeys) { - s.append('\n').append(key.getKey()).append(" = ").append(getData().get(key)); + s.append('\n').append(key.toString2()); } } if (!isSafe()) { @@ -408,10 +492,7 @@ this.source = source; } - /** - * - * @throws IOException if any - */ + /** @throws IOException if any */ protected void loadFromSource() throws IOException { if (source != null) { return; @@ -420,7 +501,7 @@ } protected void loadFromDefaultValue() throws IOException { - for (ConfigPropertyKey propertyKey : universe) { + for (ConfigPropertyKey propertyKey : universe) { Object defaultValue = propertyKey.getDefaultValue(); if (defaultValue != null) { setProperty(propertyKey, defaultValue); @@ -429,7 +510,7 @@ } protected void loadFromSystem() { - for (ConfigPropertyKey propertyKey : universe) { + for (ConfigPropertyKey propertyKey : universe) { Object val = System.getProperty(propertyKey.getKey()); if (val != null) { setProperty(propertyKey, val); @@ -438,7 +519,7 @@ } protected void loadFromEnv() { - for (ConfigPropertyKey propertyKey : universe) { + for (ConfigPropertyKey propertyKey : universe) { Object val = System.getenv(propertyKey.getKey()); if (val != null) { setProperty(propertyKey, val); @@ -453,8 +534,8 @@ * @param def the def to use * @param value the value to set */ - protected void addProperty(ConfigPropertyKey def, Object value) { - getData().put(def, value); + protected void addProperty(ConfigPropertyKey def, T value) { + def.setCurrentValue(value); if (!safeKeys.contains(def)) { safeKeys.add(def); } @@ -466,11 +547,11 @@ * * @param def the def to use */ - protected void removeProperty(ConfigPropertyKey def) { - getData().remove(def); - if (safeKeys.contains(def)) { + protected void removeProperty(ConfigPropertyKey def) { + def.setCurrentValue(null); + /*if (safeKeys.contains(def)) { safeKeys.remove(def); - } + }*/ } /** @@ -484,85 +565,6 @@ } /** - * Set the value for a given property using his def. - * - * @param def the given key to use - * @param value the given valuer to set - */ - protected void setProperty(ConfigPropertyKey def, Object value) { - checkAuthorizedKey(def); - if (value == null) { - removeProperty(def); - return; - } - - Class klass = def.getType(); - String key = def.getKey(); - - if (klass == String.class) { - addProperty(def, String.valueOf(value)); - return; - } - - if (value instanceof String) { - // make a conversion from String - Object typeValue = convert(klass, value); - if (typeValue == null) { - addUnsafeData(key, value); - } else { - addProperty(def, typeValue); - } - return; - } - - if (value.getClass() == klass) { - // add a matching typed value - addProperty(def, value); - return; - } - - Object value2 = value; - if (klass.isEnum()) { - // try an Enum conversion from ordinal - value2 = ConvertUtils.lookup(klass).convert(klass, value); - if (value2 != null && value2.getClass() == klass) { - // add a matching typed value after conversion - addProperty(def, value2); - } - } - if (value2 == null) { - addUnsafeData(key, value); - } - } - - /** - * Convert the given o object to the type klass - * - * @param klass the class of value to extract - * @param o the original value - * @return the converted value - */ - protected Object convert(Class klass, Object o) { - if (o == null) { - return null; - } - Object result; - if (klass == String.class) { - result = o; - } else { - if (o.getClass() == String.class) { - result = ConvertUtils.convert(String.valueOf(o), klass); - } else { - result = o; - } - } - if (result != null && !klass.isAssignableFrom(result.getClass())) { - result = null; - } - return result; - } - - /** * Update unvierse after a load(XXX) method. *

* The data to inject are stored in the {@link #tmp}. @@ -575,12 +577,12 @@ // tmp contains new data to digest for (Object o : tmp.keySet()) { String kStr = o + ""; - ConfigPropertyKey key = getKey(kStr); + ConfigPropertyKey key = getKey(kStr); Object value = tmp.get(o); - if (key != null && universe.contains(key)) { - setProperty(key, value); - } else { + if (key == null) { addUnsafeData(kStr, value); + } else { + setProperty(key, value); } } } finally { @@ -594,8 +596,8 @@ * @param key la clef non typée de la propriété * @return la clef typée ou null si n'existe pas */ - protected ConfigPropertyKey getKey(String key) { - for (ConfigPropertyKey configKey : universe) { + protected ConfigPropertyKey getKey(String key) { + for (ConfigPropertyKey configKey : universe) { if (configKey.getKey().equals(key)) { return configKey; } @@ -612,14 +614,6 @@ return tmp; } - /** @return the lazy data instance */ - protected Map getData() { - if (data == null) { - data = new TreeMap(); - } - return data; - } - /** @return the lazy unsafeData instance */ protected Map getUnsafeData() { if (unsafeData == null) { @@ -640,4 +634,22 @@ throw new IllegalArgumentException(_("lutinutil.error.config.unauthorized.key", def, universe.toString())); } } + + public void clear(boolean b) { + for (ConfigPropertyKey key : getModifiedKeys()) { + key.clear(b); + } + } + + public void clearModified() { + for (ConfigPropertyKey key : getModifiedKeys()) { + key.clearModified(); + } + } + + public void reset() { + for (ConfigPropertyKey key : getModifiedKeys()) { + key.reset(); + } + } }