X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fresources%2FBundle.java;h=84efceafabfacac5d1edf887dc49f3542bd76725;hb=5ddc36eacad78641be59db473f9bae9bad47eb20;hp=40177da6cbfc23050e4e266d65253fde52060f27;hpb=cd0c27d2e457ea19fcd9def879e1534a528292c2;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/resources/Bundle.java b/src/be/nikiroo/utils/resources/Bundle.java index 40177da..84efcea 100644 --- a/src/be/nikiroo/utils/resources/Bundle.java +++ b/src/be/nikiroo/utils/resources/Bundle.java @@ -1,6 +1,5 @@ package be.nikiroo.utils.resources; -import java.awt.Color; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; @@ -20,6 +19,8 @@ import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; +import be.nikiroo.utils.resources.Meta.Format; + /** * This class encapsulate a {@link ResourceBundle} in UTF-8. It allows to * retrieve values associated to an enumeration, and allows some additional @@ -73,6 +74,42 @@ public class Bundle> { setBundle(name, Locale.getDefault(), false); } + /** + * Check if the setting is set into this {@link Bundle}. + * + * @param id + * the id of the setting to check + * @param includeDefaultValue + * TRUE to only return false when the setting is not set AND + * there is no default value + * + * @return TRUE if the setting is set + */ + public boolean isSet(E id, boolean includeDefaultValue) { + return isSet(id.name(), includeDefaultValue); + } + + /** + * Check if the setting is set into this {@link Bundle}. + * + * @param name + * the id of the setting to check + * @param includeDefaultValue + * TRUE to only return false when the setting is explicitly set + * to NULL (and not just "no set") in the change maps + * + * @return TRUE if the setting is set + */ + protected boolean isSet(String name, boolean includeDefaultValue) { + if (getString(name, null) == null) { + if (!includeDefaultValue || getString(name, "") == null) { + return false; + } + } + + return true; + } + /** * Return the value associated to the given id as a {@link String}. * @@ -83,14 +120,71 @@ public class Bundle> { * resource file) */ public String getString(E id) { - return getString(id.name()); + return getString(id, null); } /** - * Set the value associated to the given id as a {@link String}. + * Return the value associated to the given id as a {@link String}. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file + * + * @return the associated value, or def if not found (not present + * in the resource file) + */ + public String getString(E id, String def) { + return getString(id, def, -1); + } + + /** + * Return the value associated to the given id as a {@link String}. + *

+ * If no value is associated (or if it is empty!), take the default one if + * any. * * @param id * the id of the value to get + * @param def + * the default value when it is not present in the config file + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + * @return the associated value, def if not found (not present in + * the resource file) or NULL if the item is specified (not -1) and + * does not exist + */ + public String getString(E id, String def, int item) { + String rep = getString(id.name(), null); + if (rep == null) { + rep = getMetaDef(id.name()); + } + + if (rep.isEmpty()) { + return def; + } + + if (item >= 0) { + List values = BundleHelper.parseList(rep, item); + if (values != null && item < values.size()) { + return values.get(item); + } + + return null; + } + + return rep; + } + + /** + * Set the value associated to the given id as a {@link String}. + * + * @param id + * the id of the value to set * @param value * the value * @@ -99,11 +193,34 @@ public class Bundle> { setString(id.name(), value); } + /** + * Set the value associated to the given id as a {@link String}. + * + * @param id + * the id of the value to set + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + */ + public void setString(E id, String value, int item) { + if (item < 0) { + setString(id.name(), value); + } else { + List values = getList(id); + setString(id.name(), BundleHelper.fromList(values, value, item)); + } + } + /** * Return the value associated to the given id as a {@link String} suffixed * with the runtime value "_suffix" (that is, "_" and suffix). *

* Will only accept suffixes that form an existing id. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get @@ -114,14 +231,61 @@ public class Bundle> { * resource file) */ public String getStringX(E id, String suffix) { + return getStringX(id, suffix, null, -1); + } + + /** + * Return the value associated to the given id as a {@link String} suffixed + * with the runtime value "_suffix" (that is, "_" and suffix). + *

+ * Will only accept suffixes that form an existing id. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param suffix + * the runtime suffix + * @param def + * the default value when it is not present in the config file + * + * @return the associated value, or NULL if not found (not present in the + * resource file) + */ + public String getStringX(E id, String suffix, String def) { + return getStringX(id, suffix, def, -1); + } + + /** + * Return the value associated to the given id as a {@link String} suffixed + * with the runtime value "_suffix" (that is, "_" and suffix). + *

+ * Will only accept suffixes that form an existing id. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param suffix + * the runtime suffix + * @param def + * the default value when it is not present in the config file + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + * @return the associated value, def if not found (not present in + * the resource file), NULL if the item is specified (not -1) but + * does not exist and NULL if bad key + */ + public String getStringX(E id, String suffix, String def, int item) { String key = id.name() + (suffix == null ? "" : "_" + suffix.toUpperCase()); try { id = Enum.valueOf(type, key); - return getString(id); + return getString(id, def, item); } catch (IllegalArgumentException e) { - } return null; @@ -134,26 +298,47 @@ public class Bundle> { * Will only accept suffixes that form an existing id. * * @param id - * the id of the value to get + * the id of the value to set * @param suffix * the runtime suffix * @param value * the value */ public void setStringX(E id, String suffix, String value) { + setStringX(id, suffix, value, -1); + } + + /** + * Set the value associated to the given id as a {@link String} suffixed + * with the runtime value "_suffix" (that is, "_" and suffix). + *

+ * Will only accept suffixes that form an existing id. + * + * @param id + * the id of the value to set + * @param suffix + * the runtime suffix + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + */ + public void setStringX(E id, String suffix, String value, int item) { String key = id.name() + (suffix == null ? "" : "_" + suffix.toUpperCase()); try { id = Enum.valueOf(type, key); - setString(id, value); + setString(id, value, item); } catch (IllegalArgumentException e) { - } } /** * Return the value associated to the given id as a {@link Boolean}. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get @@ -161,41 +346,89 @@ public class Bundle> { * @return the associated value */ public Boolean getBoolean(E id) { - String str = getString(id); - if (str != null && str.length() > 0) { - if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on") - || str.equalsIgnoreCase("yes")) - return true; - if (str.equalsIgnoreCase("false") || str.equalsIgnoreCase("off") - || str.equalsIgnoreCase("no")) - return false; + return BundleHelper.parseBoolean(getString(id), -1); + } + /** + * Return the value associated to the given id as a {@link Boolean}. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a boolean value + * + * @return the associated value + */ + public boolean getBoolean(E id, boolean def) { + Boolean value = getBoolean(id); + if (value != null) { + return value; } - return null; + return def; } /** * Return the value associated to the given id as a {@link Boolean}. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get * @param def * the default value when it is not present in the config file or * if it is not a boolean value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays * * @return the associated value */ - public boolean getBoolean(E id, boolean def) { - Boolean b = getBoolean(id); - if (b != null) - return b; + public Boolean getBoolean(E id, boolean def, int item) { + String value = getString(id); + if (value != null) { + return BundleHelper.parseBoolean(value, item); + } return def; } + /** + * Set the value associated to the given id as a {@link Boolean}. + * + * @param id + * the id of the value to set + * @param value + * the value + * + */ + public void setBoolean(E id, boolean value) { + setBoolean(id, value, -1); + } + + /** + * Set the value associated to the given id as a {@link Boolean}. + * + * @param id + * the id of the value to set + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + */ + public void setBoolean(E id, boolean value, int item) { + setString(id, BundleHelper.fromBoolean(value), item); + } + /** * Return the value associated to the given id as an {@link Integer}. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get @@ -203,9 +436,9 @@ public class Bundle> { * @return the associated value */ public Integer getInteger(E id) { - try { - return Integer.parseInt(getString(id)); - } catch (Exception e) { + String value = getString(id); + if (value != null) { + return BundleHelper.parseInteger(value, -1); } return null; @@ -213,6 +446,8 @@ public class Bundle> { /** * Return the value associated to the given id as an int. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get @@ -223,15 +458,72 @@ public class Bundle> { * @return the associated value */ public int getInteger(E id, int def) { - Integer i = getInteger(id); - if (i != null) - return i; + Integer value = getInteger(id); + if (value != null) { + return value; + } return def; } + /** + * Return the value associated to the given id as an int. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a int value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + * @return the associated value + */ + public Integer getInteger(E id, int def, int item) { + String value = getString(id); + if (value != null) { + return BundleHelper.parseInteger(value, item); + } + + return def; + } + + /** + * Set the value associated to the given id as a {@link Integer}. + * + * @param id + * the id of the value to set + * @param value + * the value + * + */ + public void setInteger(E id, int value) { + setInteger(id, value, -1); + } + + /** + * Set the value associated to the given id as a {@link Integer}. + * + * @param id + * the id of the value to set + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + */ + public void setInteger(E id, int value, int item) { + setString(id, BundleHelper.fromInteger(value), item); + } + /** * Return the value associated to the given id as a {@link Character}. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get @@ -239,105 +531,278 @@ public class Bundle> { * @return the associated value */ public Character getCharacter(E id) { - String s = getString(id).trim(); - if (s.length() > 0) { - return s.charAt(0); + return BundleHelper.parseCharacter(getString(id), -1); + } + + /** + * Return the value associated to the given id as a {@link Character}. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a char value + * + * @return the associated value + */ + public char getCharacter(E id, char def) { + Character value = getCharacter(id); + if (value != null) { + return value; } - return null; + return def; } /** * Return the value associated to the given id as a {@link Character}. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get * @param def * the default value when it is not present in the config file or * if it is not a char value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays * * @return the associated value */ - public char getCharacter(E id, char def) { - String s = getString(id).trim(); - if (s.length() > 0) { - return s.charAt(0); + public Character getCharacter(E id, char def, int item) { + String value = getString(id); + if (value != null) { + return BundleHelper.parseCharacter(value, item); } return def; } /** - * Return the value associated to the given id as a {@link Color}. + * Set the value associated to the given id as a {@link Character}. + * + * @param id + * the id of the value to set + * @param value + * the value + * + */ + public void setCharacter(E id, char value) { + setCharacter(id, value, -1); + } + + /** + * Set the value associated to the given id as a {@link Character}. + * + * @param id + * the id of the value to set + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + */ + public void setCharacter(E id, char value, int item) { + setString(id, BundleHelper.fromCharacter(value), item); + } + + /** + * Return the value associated to the given id as a colour if it is found + * and can be parsed. + *

+ * The returned value is an ARGB value. + *

+ * If no value is associated, take the default one if any. * * @param id * the id of the value to get * * @return the associated value */ - public Color getColor(E id) { - Color color = null; + public Integer getColor(E id) { + return BundleHelper.parseColor(getString(id), -1); + } - String bg = getString(id).trim(); - if (bg.startsWith("#") && (bg.length() == 7 || bg.length() == 9)) { - try { - int r = Integer.parseInt(bg.substring(1, 3), 16); - int g = Integer.parseInt(bg.substring(3, 5), 16); - int b = Integer.parseInt(bg.substring(5, 7), 16); - int a = 255; - if (bg.length() == 9) { - a = Integer.parseInt(bg.substring(7, 9), 16); - } - color = new Color(r, g, b, a); - } catch (NumberFormatException e) { - color = null; // no changes - } + /** + * Return the value associated to the given id as a colour if it is found + * and can be parsed. + *

+ * The returned value is an ARGB value. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a char value + * + * @return the associated value + */ + public int getColor(E id, int def) { + Integer value = getColor(id); + if (value != null) { + return value; } - // Try by name if still not found - if (color == null) { - try { - Field field = Color.class.getField(bg); - color = (Color) field.get(null); - } catch (Exception e) { - } + return def; + } + + /** + * Return the value associated to the given id as a colour if it is found + * and can be parsed. + *

+ * The returned value is an ARGB value. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a char value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + * @return the associated value + */ + public Integer getColor(E id, int def, int item) { + String value = getString(id); + if (value != null) { + return BundleHelper.parseColor(value, item); } - // - return color; + return def; } /** - * Set the value associated to the given id as a {@link Color}. + * Set the value associated to the given id as a colour. + *

+ * The value is a BGRA value. * * @param id * the id of the value to set * @param color - * the new color + * the new colour */ - public void setColor(E id, Color color) { - // Check for named colours first - try { - Field[] fields = Color.class.getFields(); - for (Field field : fields) { - if (field.equals(color)) { - setString(id, field.getName()); - return; - } - } - } catch (Exception e) { + public void setColor(E id, Integer color) { + setColor(id, color, -1); + } + + /** + * Set the value associated to the given id as a Color. + * + * @param id + * the id of the value to set + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + */ + public void setColor(E id, int value, int item) { + setString(id, BundleHelper.fromColor(value), item); + } + + /** + * Return the value associated to the given id as a list of values if it is + * found and can be parsed. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * + * @return the associated list, empty if the value is empty, NULL if it is + * not found or cannot be parsed as a list + */ + public List getList(E id) { + return BundleHelper.parseList(getString(id), -1); + } + + /** + * Return the value associated to the given id as a list of values if it is + * found and can be parsed. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a char value + * + * @return the associated list, empty if the value is empty, NULL if it is + * not found or cannot be parsed as a list + */ + public List getList(E id, List def) { + List value = getList(id); + if (value != null) { + return value; } - // - String r = Integer.toString(color.getRed(), 16); - String g = Integer.toString(color.getGreen(), 16); - String b = Integer.toString(color.getBlue(), 16); - String a = ""; - if (color.getAlpha() < 255) { - a = Integer.toString(color.getAlpha(), 16); + return def; + } + + /** + * Return the value associated to the given id as a list of values if it is + * found and can be parsed. + *

+ * If no value is associated, take the default one if any. + * + * @param id + * the id of the value to get + * @param def + * the default value when it is not present in the config file or + * if it is not a char value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + * @return the associated list, empty if the value is empty, NULL if it is + * not found or cannot be parsed as a list + */ + public List getList(E id, List def, int item) { + String value = getString(id); + if (value != null) { + return BundleHelper.parseList(value, item); } - setString(id, "#" + r + g + b + a); + return def; + } + + /** + * Set the value associated to the given id as a list of values. + * + * @param id + * the id of the value to set + * @param list + * the new list of values + */ + public void setList(E id, List list) { + setList(id, list, -1); + } + + /** + * Set the value associated to the given id as a {@link List}. + * + * @param id + * the id of the value to set + * @param value + * the value + * @param item + * the item number to get for an array of values, or -1 for + * non-arrays + * + */ + public void setList(E id, List value, int item) { + setString(id, BundleHelper.fromList(value), item); } /** @@ -399,6 +864,40 @@ public class Bundle> { writer.close(); } + /** + * Delete the .properties file. + *

+ * Will use the most likely candidate as base if the file does not already + * exists and this resource is translatable (for instance, "en_US" will use + * "en" as a base if the resource is a translation file). + *

+ * Will delete the files in {@link Bundles#getDirectory()}; it MUST + * be set. + * + * @return TRUE if the file was deleted + */ + public boolean deleteFile() { + return deleteFile(Bundles.getDirectory()); + } + + /** + * Delete the .properties file. + *

+ * Will use the most likely candidate as base if the file does not already + * exists and this resource is translatable (for instance, "en_US" will use + * "en" as a base if the resource is a translation file). + * + * @param path + * the path where the .properties files are, MUST NOT be + * NULL + * + * @return TRUE if the file was deleted + */ + public boolean deleteFile(String path) { + File file = getUpdateFile(path); + return file.delete(); + } + /** * The description {@link TransBundle}, that is, a {@link TransBundle} * dedicated to the description of the values of the given {@link Bundle} @@ -435,15 +934,43 @@ public class Bundle> { } /** - * Get the value for the given key if it exists in the internal map, or NULL - * if not. + * The default {@link Meta#def()} value for the given enumeration name. + * + * @param id + * the enumeration name (the "id") + * + * @return the def value in the {@link MetaInfo} or "" if none (never NULL) + */ + protected String getMetaDef(String id) { + String rep = ""; + try { + Meta meta = type.getDeclaredField(id).getAnnotation(Meta.class); + rep = meta.def(); + } catch (NoSuchFieldException e) { + } catch (SecurityException e) { + } + + if (rep == null) { + rep = ""; + } + + return rep; + } + + /** + * Get the value for the given key if it exists in the internal map, or + * def if not. + *

+ * DO NOT get the default meta value (MetaInfo.def()). * * @param key * the key to check for + * @param def + * the default value when it is not present in the internal map * - * @return the value, or NULL + * @return the value, or def if not found */ - protected String getString(String key) { + protected String getString(String key, String def) { if (changeMap.containsKey(key)) { return changeMap.get(key); } @@ -452,7 +979,7 @@ public class Bundle> { return map.get(key); } - return null; + return def; } /** @@ -483,37 +1010,41 @@ public class Bundle> { Meta.Format format = meta.format(); String[] list = meta.list(); boolean nullable = meta.nullable(); - String info = meta.info(); + String def = meta.def(); boolean array = meta.array(); // Default, empty values -> NULL - if (desc.length() + list.length + info.length() == 0 && !group - && nullable && format == Meta.Format.STRING) { + if (desc.length() + list.length + def.length() == 0 && !group + && nullable && format == Format.STRING) { return null; } StringBuilder builder = new StringBuilder(); - builder.append("# ").append(desc); - if (desc.length() > 20) { - builder.append("\n#"); + for (String line : desc.split("\n")) { + builder.append("# ").append(line).append("\n"); } if (group) { - builder.append("This item is used as a group, its content is not expected to be used."); + builder.append("# This item is used as a group, its content is not expected to be used."); } else { - builder.append(" (FORMAT: ").append(format) - .append(nullable ? "" : " (required)"); - builder.append(") ").append(info); + builder.append("# (FORMAT: ").append(format) + .append(nullable ? "" : ", required"); + builder.append(") "); if (list.length > 0) { - builder.append("\n# ALLOWED VALUES:"); + builder.append("\n# ALLOWED VALUES: "); + boolean first = true; for (String value : list) { - builder.append(" \"").append(value).append("\""); + if (!first) { + builder.append(", "); + } + builder.append(BundleHelper.escape(value)); + first = false; } } if (array) { - builder.append("\n# (This item accept a list of comma-separated values)"); + builder.append("\n# (This item accepts a list of ^escaped comma-separated values)"); } } @@ -545,8 +1076,11 @@ public class Bundle> { } /** - * Write the given id to the config file, i.e., "MY_ID = my_curent_value" - * followed by a new line + * Write the given data to the config file, i.e., "MY_ID = my_curent_value" + * followed by a new line. + *

+ * Will prepend a # sign if the is is not set (see + * {@link Bundle#isSet(Enum, boolean)}). * * @param writer * the {@link Writer} to write into @@ -557,12 +1091,15 @@ public class Bundle> { * in case of IO error */ protected void writeValue(Writer writer, E id) throws IOException { - writeValue(writer, id.name(), getString(id)); + boolean set = isSet(id, false); + writeValue(writer, id.name(), getString(id), set); } /** * Write the given data to the config file, i.e., "MY_ID = my_curent_value" - * followed by a new line + * followed by a new line. + *

+ * Will prepend a # sign if the is is not set. * * @param writer * the {@link Writer} to write into @@ -570,12 +1107,19 @@ public class Bundle> { * the id to write * @param value * the id's value + * @param set + * the value is set in this {@link Bundle} * * @throws IOException * in case of IO error */ - protected void writeValue(Writer writer, String id, String value) - throws IOException { + protected void writeValue(Writer writer, String id, String value, + boolean set) throws IOException { + + if (!set) { + writer.write('#'); + } + writer.write(id); writer.write(" = "); @@ -620,14 +1164,16 @@ public class Bundle> { protected void setBundle(Enum name, Locale locale, boolean resetToDefault) { changeMap.clear(); String dir = Bundles.getDirectory(); + String bname = type.getPackage().getName() + "." + name.name(); boolean found = false; if (!resetToDefault && dir != null) { + // Look into Bundles.getDirectory() for .properties files try { File file = getPropertyFile(dir, name.name(), locale); if (file != null) { Reader reader = new InputStreamReader(new FileInputStream( - file), "UTF8"); + file), "UTF-8"); resetMap(new PropertyResourceBundle(reader)); found = true; } @@ -637,35 +1183,44 @@ public class Bundle> { } if (!found) { - String bname = type.getPackage().getName() + "." + name.name(); + // Look into the package itself for resources try { resetMap(ResourceBundle .getBundle(bname, locale, type.getClassLoader(), new FixedResourceBundleControl())); + found = true; + } catch (MissingResourceException e) { } catch (Exception e) { - // We have no bundle for this Bundle - System.err.println("No bundle found for: " + bname); - resetMap(null); + e.printStackTrace(); } } + + if (!found) { + // We have no bundle for this Bundle + System.err.println("No bundle found for: " + bname); + resetMap(null); + } } /** - * Reset the backing map to the content of the given bundle, or empty if - * bundle is NULL. + * Reset the backing map to the content of the given bundle, or with NULL + * values if bundle is NULL. * * @param bundle * the bundle to copy */ protected void resetMap(ResourceBundle bundle) { this.map.clear(); - if (bundle != null) { - for (E field : type.getEnumConstants()) { + for (Field field : type.getDeclaredFields()) { try { - String value = bundle.getString(field.name()); - this.map.put(field.name(), - value == null ? null : value.trim()); + Meta meta = field.getAnnotation(Meta.class); + if (meta != null) { + E id = Enum.valueOf(type, field.getName()); + String value = bundle.getString(id.name()); + this.map.put(id.name(), + value == null ? null : value.trim()); + } } catch (MissingResourceException e) { } } @@ -698,7 +1253,7 @@ public class Bundle> { if (snap instanceof Map) { changeMap = (Map) snap; } else { - throw new Error( + throw new RuntimeException( "Restoring changes in a Bundle must be done on a changes snapshot, " + "or NULL to discard current changes"); } @@ -740,7 +1295,7 @@ public class Bundle> { if (file.exists()) { break; } - + file = null; }