From a69373087dd57f2595e7bf53bff9feb054d0a11f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 31 Mar 2010 13:59:55 -0700 Subject: [PATCH] Add Java 6's ResourceBundle/Properties API. I've pretty much taken the upstream ResourceBundle implementations as-is, putting back our string-to-locale conversion, removing a bit of duplication and non-free, non-spec EBCDIC support, and hard-coding the text of the MissingResourceExceptions (since harmony's changed its message catalog from ours, so I had to touch those bits of the code anyway). (Why haven't I bothered to pay much attention to the resource bundle implementations? Because I already rewrote our only code that was using them to not use them, and third-party developers should be using Android's resource system instead. There's very little chance anyone needs Java resource bundles. I paid some attention to Properties, because they're still somewhat useful.) Also remove various unused messages, and update our tests. I've mostly _not_ taken the upstream tests, because it would require a lot of work that we'll be doing anyway when we switch to using their test suite properly. I ran the jtreg tests we're able to run, and the normal-case ones (plus the stress test) seemed okay. Bug: 2497395 Change-Id: I91606df0dc1a45e6974fbb27a0d334af87254f0b --- .../main/java/java/util/ListResourceBundle.java | 23 +- .../luni/src/main/java/java/util/Properties.java | 200 ++-- .../java/java/util/PropertyResourceBundle.java | 37 +- .../src/main/java/java/util/ResourceBundle.java | 785 ++++++++++++++- .../harmony/luni/internal/nls/messages.properties | 5 - .../harmony/luni/util/ExternalMessages.properties | 102 -- .../java/tests/api/java/util/PropertiesTest.java | 1057 ++++++++++++++------ .../tests/api/java/util/ResourceBundleTest.java | 2 +- .../security/tests/java/security/ProviderTest.java | 2 +- 9 files changed, 1647 insertions(+), 566 deletions(-) diff --git a/libcore/luni/src/main/java/java/util/ListResourceBundle.java b/libcore/luni/src/main/java/java/util/ListResourceBundle.java index 6206ee66d..278f130bb 100644 --- a/libcore/luni/src/main/java/java/util/ListResourceBundle.java +++ b/libcore/luni/src/main/java/java/util/ListResourceBundle.java @@ -21,7 +21,7 @@ package java.util; * {@code ListResourceBundle} is the abstract superclass of classes which provide * resources by implementing the {@code getContents()} method to return * the list of resources. - * + * * @see ResourceBundle * @since 1.1 */ @@ -36,20 +36,15 @@ public abstract class ListResourceBundle extends ResourceBundle { } /** - * Returns an {@code Object} array which contains the resources of this + * Returns an {@code Object} array containing the resources of this * {@code ListResourceBundle}. Each element in the array is an array of two * elements, the first is the resource key string and the second is the * resource. - * + * * @return a {@code Object} array containing the resources. */ protected abstract Object[][] getContents(); - /** - * Returns the names of the resources contained in this {@code ListResourceBundle}. - * - * @return an {@code Enumeration} of the resource names. - */ @Override public Enumeration getKeys() { initializeTable(); @@ -131,4 +126,16 @@ public abstract class ListResourceBundle extends ResourceBundle { } } } + + /** + * Returns a set of the keys in this ResourceBundle but not in its parents. + * + * @return a set of the keys in this ResourceBundle but not in its parents. + * @since 1.6 + * @hide + */ + protected Set handleKeySet() { + initializeTable(); + return table.keySet(); + } } diff --git a/libcore/luni/src/main/java/java/util/Properties.java b/libcore/luni/src/main/java/java/util/Properties.java index ce42f9a70..45bbb6f75 100644 --- a/libcore/luni/src/main/java/java/util/Properties.java +++ b/libcore/luni/src/main/java/java/util/Properties.java @@ -17,14 +17,17 @@ package java.util; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.BufferedInputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.Reader; import java.io.StringReader; +import java.io.Writer; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; @@ -43,10 +46,8 @@ import org.xml.sax.SAXParseException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; -// BEGIN android-added import org.w3c.dom.Node; import org.w3c.dom.Text; -// END android-added import org.apache.harmony.luni.internal.nls.Messages; import org.apache.harmony.luni.util.PriviAction; @@ -106,7 +107,7 @@ public class Properties extends Hashtable { private void dumpString(StringBuilder buffer, String string, boolean key) { int i = 0; if (!key && i < string.length() && string.charAt(i) == ' ') { - buffer.append("\\ "); //$NON-NLS-1$ + buffer.append("\\ "); i++; } @@ -114,16 +115,16 @@ public class Properties extends Hashtable { char ch = string.charAt(i); switch (ch) { case '\t': - buffer.append("\\t"); //$NON-NLS-1$ + buffer.append("\\t"); break; case '\n': - buffer.append("\\n"); //$NON-NLS-1$ + buffer.append("\\n"); break; case '\f': - buffer.append("\\f"); //$NON-NLS-1$ + buffer.append("\\f"); break; case '\r': - buffer.append("\\r"); //$NON-NLS-1$ + buffer.append("\\r"); break; default: if ("\\#!=:".indexOf(ch) >= 0 || (key && ch == ' ')) { @@ -133,9 +134,9 @@ public class Properties extends Hashtable { buffer.append(ch); } else { String hex = Integer.toHexString(ch); - buffer.append("\\u"); //$NON-NLS-1$ + buffer.append("\\u"); for (int j = 0; j < 4 - hex.length(); j++) { - buffer.append("0"); //$NON-NLS-1$ + buffer.append("0"); } buffer.append(hex); } @@ -212,7 +213,7 @@ public class Properties extends Hashtable { } if (property.length() > 40) { buffer.append(property.substring(0, 37)); - buffer.append("..."); //$NON-NLS-1$ + buffer.append("..."); } else { buffer.append(property); } @@ -248,7 +249,7 @@ public class Properties extends Hashtable { } if (property.length() > 40) { buffer.append(property.substring(0, 37)); - buffer.append("..."); //$NON-NLS-1$ + buffer.append("..."); } else { buffer.append(property); } @@ -259,33 +260,45 @@ public class Properties extends Hashtable { /** * Loads properties from the specified {@code InputStream}. The encoding is - * ISO8859-1. The {@code Properties} file is interpreted according to the - * following rules: + * ISO8859-1. + * @param in the {@code InputStream} + * @throws IOException + */ + public synchronized void load(InputStream in) throws IOException { + if (in == null) { + throw new NullPointerException(); + } + load(new InputStreamReader(in, "ISO8859_1")); + } + + /** + * Loads properties from the specified {@code Reader}. + * The properties file is interpreted according to the following rules: *
    *
  • Empty lines are ignored.
  • *
  • Lines starting with either a "#" or a "!" are comment lines and are * ignored.
  • *
  • A backslash at the end of the line escapes the following newline - * character ("\r", "\n", "\r\n"). If there's a whitespace after the + * character ("\r", "\n", "\r\n"). If there's whitespace after the * backslash it will just escape that whitespace instead of concatenating * the lines. This does not apply to comment lines.
  • *
  • A property line consists of the key, the space between the key and * the value, and the value. The key goes up to the first whitespace, "=" or * ":" that is not escaped. The space between the key and the value contains - * either one whitespace, one "=" or one ":" and any number of additional - * whitespaces before and after that character. The value starts with the + * either one whitespace, one "=" or one ":" and any amount of additional + * whitespace before and after that character. The value starts with the * first character after the space between the key and the value.
  • *
  • Following escape sequences are recognized: "\ ", "\\", "\r", "\n", * "\!", "\#", "\t", "\b", "\f", and "\uXXXX" (unicode character).
  • *
* - * @param in - * the {@code InputStream}. + * @param in the {@code Reader} * @throws IOException - * if error occurs during reading from the {@code InputStream}. + * @since 1.6 + * @hide */ @SuppressWarnings("fallthrough") - public synchronized void load(InputStream in) throws IOException { + public synchronized void load(Reader in) throws IOException { if (in == null) { throw new NullPointerException(); } @@ -294,25 +307,14 @@ public class Properties extends Hashtable { int offset = 0, keyLength = -1, intVal; boolean firstChar = true; - BufferedInputStream bis = new BufferedInputStream(in); + BufferedReader br = new BufferedReader(in); while (true) { - intVal = bis.read(); + intVal = br.read(); if (intVal == -1) { - // if mode is UNICODE but has less than 4 hex digits, should - // throw an IllegalArgumentException - // luni.08=Invalid Unicode sequence: expected format \\uxxxx - if (mode == UNICODE && count < 4) { - throw new IllegalArgumentException(Messages.getString("luni.08")); //$NON-NLS-1$ - } - // if mode is SLASH and no data is read, should append '\u0000' - // to buf - if (mode == SLASH) { - buf[offset++] = '\u0000'; - } break; } - nextChar = (char) (intVal & 0xff); + nextChar = (char) intVal; if (offset == buf.length) { char[] newBuf = new char[buf.length * 2]; @@ -327,8 +329,7 @@ public class Properties extends Hashtable { continue; } } else if (count <= 4) { - // luni.09=Invalid Unicode sequence: illegal character - throw new IllegalArgumentException(Messages.getString("luni.09")); //$NON-NLS-1$ + throw new IllegalArgumentException("Invalid Unicode sequence: illegal character"); } mode = NONE; buf[offset++] = (char) unicode; @@ -371,11 +372,10 @@ public class Properties extends Hashtable { case '!': if (firstChar) { while (true) { - intVal = bis.read(); + intVal = br.read(); if (intVal == -1) { break; } - // & 0xff not required nextChar = (char) intVal; if (nextChar == '\r' || nextChar == '\n') { break; @@ -443,39 +443,67 @@ public class Properties extends Hashtable { } buf[offset++] = nextChar; } + if (mode == UNICODE && count <= 4) { + throw new IllegalArgumentException("Invalid Unicode sequence: expected format \\uxxxx"); + } if (keyLength == -1 && offset > 0) { keyLength = offset; } if (keyLength >= 0) { String temp = new String(buf, 0, offset); - put(temp.substring(0, keyLength), temp.substring(keyLength)); + String key = temp.substring(0, keyLength); + String value = temp.substring(keyLength); + if (mode == SLASH) { + value += "\u0000"; + } + put(key, value); } } /** - * Returns all of the property names that this {@code Properties} object - * contains. - * - * @return an {@code Enumeration} containing the names of all properties - * that this {@code Properties} object contains. + * Returns all of the property names (keys) in this {@code Properties} object. */ public Enumeration propertyNames() { - if (defaults == null) { - return keys(); - } + Hashtable selected = new Hashtable(); + selectProperties(selected, false); + return selected.keys(); + } - Hashtable set = new Hashtable(defaults - .size() - + size()); - Enumeration keys = defaults.propertyNames(); - while (keys.hasMoreElements()) { - set.put(keys.nextElement(), set); + /** + * Returns those property names (keys) in this {@code Properties} object for which + * both key and value are strings. + * + * @return a set of keys in the property list + * @since 1.6 + * @hide + */ + public Set stringPropertyNames() { + Hashtable stringProperties = new Hashtable(); + selectProperties(stringProperties, true); + return Collections.unmodifiableSet(stringProperties.keySet()); + } + + private void selectProperties(Hashtable selectProperties, final boolean isStringOnly) { + if (defaults != null) { + defaults.selectProperties(selectProperties, isStringOnly); } - keys = keys(); + Enumeration keys = keys(); + Object key, value; while (keys.hasMoreElements()) { - set.put(keys.nextElement(), set); + key = keys.nextElement(); + if (isStringOnly) { + // Only select property with string key and value + if (key instanceof String) { + value = get(key); + if (value instanceof String) { + selectProperties.put(key, value); + } + } + } else { + value = get(key); + selectProperties.put(key, value); + } } - return set.keys(); } /** @@ -514,39 +542,48 @@ public class Properties extends Hashtable { return put(name, value); } + /** + * Stores the mappings in this {@code Properties} object to {@code out}, + * putting the specified comment at the beginning. The encoding is + * ISO8859-1. + * + * @param out the {@code OutputStream} + * @param comment an optional comment to be written, or null + * @throws IOException + * @throws ClassCastException if a key or value is not a string + */ + public synchronized void store(OutputStream out, String comment) throws IOException { + store(new OutputStreamWriter(out, "ISO8859_1"), comment); + } + private static String lineSeparator; /** - * Stores the mappings in this {@code Properties} to the specified {@code - * OutputStream}, putting the specified comment at the beginning. The output - * from this method is suitable for being read by the - * {@link #load(InputStream)} method. - * - * @param out the {@code OutputStream} to write to. - * @param comment the comment to put at the beginning. - * @throws IOException if an error occurs during the write to the {@code - * OutputStream}. - * @throws ClassCastException if the key or value of a mapping is not a - * {@code String}. + * Stores the mappings in this {@code Properties} object to {@code out}, + * putting the specified comment at the beginning. + * + * @param out the {@code Writer} + * @param comment an optional comment to be written, or null + * @throws IOException + * @throws ClassCastException if a key or value is not a string + * @since 1.6 + * @hide */ - public synchronized void store(OutputStream out, String comment) - throws IOException { + public synchronized void store(Writer writer, String comment) throws IOException { if (lineSeparator == null) { - lineSeparator = AccessController - .doPrivileged(new PriviAction("line.separator")); //$NON-NLS-1$ + lineSeparator = AccessController.doPrivileged(new PriviAction("line.separator")); } - StringBuilder buffer = new StringBuilder(200); - OutputStreamWriter writer = new OutputStreamWriter(out, "ISO8859_1"); //$NON-NLS-1$ if (comment != null) { - writer.write("#"); //$NON-NLS-1$ + writer.write("#"); writer.write(comment); writer.write(lineSeparator); } - writer.write("#"); //$NON-NLS-1$ + writer.write("#"); writer.write(new Date().toString()); writer.write(lineSeparator); + StringBuilder buffer = new StringBuilder(200); for (Map.Entry entry : entrySet()) { String key = (String) entry.getKey(); dumpString(buffer, key, true); @@ -585,7 +622,7 @@ public class Properties extends Hashtable { if (builder == null) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - // BEGIN android-removed + // BEGIN android-removed: we still don't support validation. // factory.setValidating(true); // END android-removed @@ -635,12 +672,7 @@ public class Properties extends Hashtable { for (int i = 0; i < entriesListLength; i++) { Element entry = (Element) entries.item(i); String key = entry.getAttribute("key"); - // BEGIN android-removed - // String value = entry.getTextContent(); - // END android-removed - // BEGIN android-added String value = getTextContent(entry); - // END android-added /* * key != null & value != null but key or(and) value can be @@ -673,7 +705,7 @@ public class Properties extends Hashtable { * @throws IOException if an error occurs during writing to the output. */ public void storeToXML(OutputStream os, String comment) throws IOException { - storeToXML(os, comment, "UTF-8"); //$NON-NLS-1$ + storeToXML(os, comment, "UTF-8"); } /** @@ -764,7 +796,7 @@ public class Properties extends Hashtable { """); } - // BEGIN android-added + // BEGIN android-added: our SAX parser still doesn't do this for us. private String getTextContent(Node node) { String result = (node instanceof Text ? ((Text) node).getData() : ""); diff --git a/libcore/luni/src/main/java/java/util/PropertyResourceBundle.java b/libcore/luni/src/main/java/java/util/PropertyResourceBundle.java index 835e892d3..5d96ead02 100644 --- a/libcore/luni/src/main/java/java/util/PropertyResourceBundle.java +++ b/libcore/luni/src/main/java/java/util/PropertyResourceBundle.java @@ -19,6 +19,7 @@ package java.util; import java.io.IOException; import java.io.InputStream; +import java.io.Reader; /** * {@code PropertyResourceBundle} loads resources from an {@code InputStream}. All resources are @@ -44,21 +45,35 @@ public class PropertyResourceBundle extends ResourceBundle { * {@code InputStream}. */ public PropertyResourceBundle(InputStream stream) throws IOException { + if (stream == null) { + throw new NullPointerException(); + } resources = new Properties(); resources.load(stream); } - + + /** + * Constructs a new resource bundle with properties read from {@code reader}. + * + * @param reader the {@code Reader} + * @throws IOException + * @since 1.6 + * @hide + */ + public PropertyResourceBundle(Reader reader) throws IOException { + resources = new Properties(); + resources.load(reader); + } + + protected Set handleKeySet(){ + return resources.stringPropertyNames(); + } + @SuppressWarnings("unchecked") private Enumeration getLocalKeys() { return (Enumeration) resources.propertyNames(); } - /** - * Returns the names of the resources contained in this - * PropertyResourceBundle. - * - * @return an Enumeration of the resource names - */ @Override public Enumeration getKeys() { if (parent == null) { @@ -107,14 +122,6 @@ public class PropertyResourceBundle extends ResourceBundle { }; } - /** - * Returns the named resource from this PropertyResourceBundle, or null if - * the resource is not found. - * - * @param key - * the name of the resource - * @return the resource object - */ @Override public Object handleGetObject(String key) { return resources.get(key); diff --git a/libcore/luni/src/main/java/java/util/ResourceBundle.java b/libcore/luni/src/main/java/java/util/ResourceBundle.java index 452ba8a2d..8901e45b9 100644 --- a/libcore/luni/src/main/java/java/util/ResourceBundle.java +++ b/libcore/luni/src/main/java/java/util/ResourceBundle.java @@ -18,17 +18,16 @@ package java.util; import com.ibm.icu4jni.util.Resources; +import dalvik.system.VMStack; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; import java.security.AccessController; import java.security.PrivilegedAction; -// BEGIN android-changed -// import org.apache.harmony.kernel.vm.VM; -import dalvik.system.VMStack; -// END android-changed -import org.apache.harmony.luni.util.Msg; - /** * {@code ResourceBundle} is an abstract class which is the superclass of classes which * provide {@code Locale}-specific resources. A bundle contains a number of named @@ -81,6 +80,10 @@ import org.apache.harmony.luni.util.Msg; */ public abstract class ResourceBundle { + private static final String UNDER_SCORE = "_"; //$NON-NLS-1$ + + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + /** * The parent of this {@code ResourceBundle} that is used if this bundle doesn't * include the requested resource. @@ -89,6 +92,8 @@ public abstract class ResourceBundle { private Locale locale; + private long lastLoadTime = 0; + static class MissingBundle extends ResourceBundle { @Override public Enumeration getKeys() { @@ -107,10 +112,6 @@ public abstract class ResourceBundle { private static final WeakHashMap> cache = new WeakHashMap>(); - // BEGIN android-added - private static Locale defaultLocale = Locale.getDefault(); - // END android-added - /** * Constructs a new instance of this class. */ @@ -121,25 +122,21 @@ public abstract class ResourceBundle { /** * Finds the named resource bundle for the default {@code Locale} and the caller's * {@code ClassLoader}. - * + * * @param bundleName * the name of the {@code ResourceBundle}. * @return the requested {@code ResourceBundle}. * @throws MissingResourceException * if the {@code ResourceBundle} cannot be found. */ - public static final ResourceBundle getBundle(String bundleName) - throws MissingResourceException { - // BEGIN android-changed - return getBundleImpl(bundleName, Locale.getDefault(), VMStack - .getCallingClassLoader()); - // END android-changed + public static final ResourceBundle getBundle(String bundleName) throws MissingResourceException { + return getBundleImpl(bundleName, Locale.getDefault(), VMStack.getCallingClassLoader()); } /** * Finds the named {@code ResourceBundle} for the specified {@code Locale} and the caller * {@code ClassLoader}. - * + * * @param bundleName * the name of the {@code ResourceBundle}. * @param locale @@ -148,17 +145,13 @@ public abstract class ResourceBundle { * @throws MissingResourceException * if the resource bundle cannot be found. */ - public static final ResourceBundle getBundle(String bundleName, - Locale locale) { - // BEGIN android-changed - return getBundleImpl(bundleName, locale, - VMStack.getCallingClassLoader()); - // END android-changed + public static final ResourceBundle getBundle(String bundleName, Locale locale) { + return getBundleImpl(bundleName, locale, VMStack.getCallingClassLoader()); } /** * Finds the named resource bundle for the specified {@code Locale} and {@code ClassLoader}. - * + * * The passed base name and {@code Locale} are used to create resource bundle names. * The first name is created by concatenating the base name with the result * of {@link Locale#toString()}. From this name all parent bundle names are @@ -210,25 +203,215 @@ public abstract class ResourceBundle { if (loader == null) { throw new NullPointerException(); } - // BEGIN android-changed - return getBundleImpl(bundleName, locale, loader); - // END android-changed + if (bundleName != null) { + ResourceBundle bundle; + if (!locale.equals(Locale.getDefault())) { + if ((bundle = handleGetBundle(bundleName, UNDER_SCORE + locale, + false, loader)) != null) { + return bundle; + } + } + if ((bundle = handleGetBundle(bundleName, UNDER_SCORE + + Locale.getDefault(), true, loader)) != null) { + return bundle; + } + throw missingResourceException(bundleName + '_' + locale, ""); + } + throw new NullPointerException(); + } + + private static MissingResourceException missingResourceException(String className, String key) { + String detail = "Can't find resource for bundle '" + className + "', key '" + key + "'"; + throw new MissingResourceException(detail, className, key); + } + + /** + * Finds the named resource bundle for the specified base name and control. + * + * @param baseName + * the base name of a resource bundle + * @param control + * the control that control the access sequence + * @return the named resource bundle + * + * @since 1.6 + * @hide + */ + public static final ResourceBundle getBundle(String baseName, ResourceBundle.Control control) { + return getBundle(baseName, Locale.getDefault(), getLoader(), control); + } + + /** + * Finds the named resource bundle for the specified base name and control. + * + * @param baseName + * the base name of a resource bundle + * @param targetLocale + * the target locale of the resource bundle + * @param control + * the control that control the access sequence + * @return the named resource bundle + * + * @since 1.6 + * @hide + */ + public static final ResourceBundle getBundle(String baseName, + Locale targetLocale, ResourceBundle.Control control) { + return getBundle(baseName, targetLocale, getLoader(), control); + } + + private static ClassLoader getLoader() { + return AccessController + .doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + ClassLoader cl = this.getClass().getClassLoader(); + if (null == cl) { + cl = ClassLoader.getSystemClassLoader(); + } + return cl; + } + }); + } + + /** + * Finds the named resource bundle for the specified base name and control. + * + * @param baseName + * the base name of a resource bundle + * @param targetLocale + * the target locale of the resource bundle + * @param loader + * the class loader to load resource + * @param control + * the control that control the access sequence + * @return the named resource bundle + * + * @since 1.6 + * @hide + */ + public static ResourceBundle getBundle(String baseName, + Locale targetLocale, ClassLoader loader, + ResourceBundle.Control control) { + boolean expired = false; + String bundleName = control.toBundleName(baseName, targetLocale); + Object cacheKey = loader != null ? (Object) loader : (Object) "null"; //$NON-NLS-1$ + Hashtable loaderCache; + // try to find in cache + synchronized (cache) { + loaderCache = cache.get(cacheKey); + if (loaderCache == null) { + loaderCache = new Hashtable(); + cache.put(cacheKey, loaderCache); + } + } + ResourceBundle result = loaderCache.get(bundleName); + if (result != null) { + long time = control.getTimeToLive(baseName, targetLocale); + if (time == 0 || time == Control.TTL_NO_EXPIRATION_CONTROL + || time + result.lastLoadTime < System.currentTimeMillis()) { + if (MISSING == result) { + throw new MissingResourceException(null, bundleName + '_' + + targetLocale, EMPTY_STRING); + } + return result; + } + expired = true; + } + // try to load + ResourceBundle ret = processGetBundle(baseName, targetLocale, loader, + control, expired, result); + + if (null != ret) { + loaderCache.put(bundleName, ret); + ret.lastLoadTime = System.currentTimeMillis(); + return ret; + } + loaderCache.put(bundleName, MISSING); + throw new MissingResourceException(null, bundleName + '_' + + targetLocale, EMPTY_STRING); + } + + private static ResourceBundle processGetBundle(String baseName, + Locale targetLocale, ClassLoader loader, + ResourceBundle.Control control, boolean expired, + ResourceBundle result) { + List locales = control.getCandidateLocales(baseName, + targetLocale); + if (null == locales) { + throw new IllegalArgumentException(); + } + List formats = control.getFormats(baseName); + if (Control.FORMAT_CLASS == formats + || Control.FORMAT_PROPERTIES == formats + || Control.FORMAT_DEFAULT == formats) { + throw new IllegalArgumentException(); + } + ResourceBundle ret = null; + ResourceBundle currentBundle = null; + ResourceBundle bundle = null; + for (Locale locale : locales) { + for (String format : formats) { + try { + if (expired) { + bundle = control.newBundle(baseName, locale, format, + loader, control.needsReload(baseName, locale, + format, loader, result, System + .currentTimeMillis())); + + } else { + try { + bundle = control.newBundle(baseName, locale, + format, loader, false); + } catch (IllegalArgumentException e) { + // do nothing + } + } + } catch (IllegalAccessException e) { + // do nothing + } catch (InstantiationException e) { + // do nothing + } catch (IOException e) { + // do nothing + } + if (null != bundle) { + if (null != currentBundle) { + currentBundle.setParent(bundle); + currentBundle = bundle; + } else { + if (null == ret) { + ret = bundle; + currentBundle = ret; + } + } + } + if (null != bundle) { + break; + } + } + } + + if ((null == ret) + || (Locale.ROOT.equals(ret.getLocale()) && (!(locales.size() == 1 && locales + .contains(Locale.ROOT))))) { + Locale nextLocale = control.getFallbackLocale(baseName, + targetLocale); + if (null != nextLocale) { + ret = processGetBundle(baseName, nextLocale, loader, control, + expired, result); + } + } + + return ret; } private static ResourceBundle getBundleImpl(String bundleName, Locale locale, ClassLoader loader) throws MissingResourceException { if (bundleName != null) { ResourceBundle bundle; - // BEGIN android-added - if (!defaultLocale.equals(Locale.getDefault())) { - cache.clear(); - defaultLocale = Locale.getDefault(); - } - // END android-added if (!locale.equals(Locale.getDefault())) { String localeName = locale.toString(); if (localeName.length() > 0) { - localeName = "_" + localeName; //$NON-NLS-1$ + localeName = UNDER_SCORE + localeName; } if ((bundle = handleGetBundle(bundleName, localeName, false, loader)) != null) { @@ -237,20 +420,19 @@ public abstract class ResourceBundle { } String localeName = Locale.getDefault().toString(); if (localeName.length() > 0) { - localeName = "_" + localeName; //$NON-NLS-1$ + localeName = UNDER_SCORE + localeName; } if ((bundle = handleGetBundle(bundleName, localeName, true, loader)) != null) { return bundle; } - throw new MissingResourceException(Msg.getString("KA029", bundleName, locale), bundleName + '_' + locale, //$NON-NLS-1$ - ""); //$NON-NLS-1$ + throw missingResourceException(bundleName + '_' + locale, ""); } throw new NullPointerException(); } /** * Returns the names of the resources contained in this {@code ResourceBundle}. - * + * * @return an {@code Enumeration} of the resource names. */ public abstract Enumeration getKeys(); @@ -259,7 +441,7 @@ public abstract class ResourceBundle { * Gets the {@code Locale} of this {@code ResourceBundle}. In case a bundle was not * found for the requested {@code Locale}, this will return the actual {@code Locale} of * this resource bundle that was found after doing a fallback. - * + * * @return the {@code Locale} of this {@code ResourceBundle}. */ public Locale getLocale() { @@ -271,7 +453,7 @@ public abstract class ResourceBundle { * cannot be found in this bundle, it falls back to the parent bundle (if * it's not null) by calling the {@link #handleGetObject} method. If the resource still * can't be found it throws a {@code MissingResourceException}. - * + * * @param key * the name of the resource. * @return the resource object. @@ -288,12 +470,12 @@ public abstract class ResourceBundle { last = theParent; theParent = theParent.parent; } while (theParent != null); - throw new MissingResourceException(Msg.getString("KA029", last.getClass().getName(), key), last.getClass().getName(), key); //$NON-NLS-1$ + throw missingResourceException(last.getClass().getName(), key); } /** * Returns the named string resource from this {@code ResourceBundle}. - * + * * @param key * the name of the resource. * @return the resource string. @@ -309,7 +491,7 @@ public abstract class ResourceBundle { /** * Returns the named resource from this {@code ResourceBundle}. - * + * * @param key * the name of the resource. * @return the resource string array. @@ -356,7 +538,7 @@ public abstract class ResourceBundle { try { Class bundleClass = Class.forName(bundleName, true, loader); - + if (ResourceBundle.class.isAssignableFrom(bundleClass)) { bundle = (ResourceBundle) bundleClass.newInstance(); } @@ -381,12 +563,13 @@ public abstract class ResourceBundle { if (stream != null) { try { try { - bundle = new PropertyResourceBundle(stream); + bundle = new PropertyResourceBundle(new InputStreamReader(stream)); } finally { stream.close(); } bundle.setLocale(locale); } catch (IOException e) { + // do nothing } } } @@ -418,7 +601,7 @@ public abstract class ResourceBundle { /** * Returns the named resource from this {@code ResourceBundle}, or null if the * resource is not found. - * + * * @param key * the name of the resource. * @return the resource object. @@ -428,7 +611,7 @@ public abstract class ResourceBundle { /** * Sets the parent resource bundle of this {@code ResourceBundle}. The parent is * searched for resources which are not found in this {@code ResourceBundle}. - * + * * @param bundle * the parent {@code ResourceBundle}. */ @@ -444,9 +627,509 @@ public abstract class ResourceBundle { return null; } + private void setLocale(Locale locale) { + this.locale = locale; + } + private void setLocale(String name) { - // BEGIN android-changed: remove duplication. - locale = Resources.localeFromString(name); - // END android-changed + setLocale(Resources.localeFromString(name)); + } + + public static final void clearCache() { + cache.remove(ClassLoader.getSystemClassLoader()); + } + + public static final void clearCache(ClassLoader loader) { + if (null == loader) { + throw new NullPointerException(); + } + cache.remove(loader); + } + + public boolean containsKey(String key) { + if (null == key) { + throw new NullPointerException(); + } + return keySet().contains(key); + } + + public Set keySet() { + Set ret = new HashSet(); + Enumeration keys = getKeys(); + while (keys.hasMoreElements()) { + ret.add(keys.nextElement()); + } + return ret; + } + + protected Set handleKeySet() { + Set set = keySet(); + Set ret = new HashSet(); + for (String key : set) { + if (null != handleGetObject(key)) { + ret.add(key); + } + } + return ret; + } + + private static class NoFallbackControl extends Control { + + static final Control NOFALLBACK_FORMAT_PROPERTIES_CONTROL = new NoFallbackControl( + JAVAPROPERTIES); + + static final Control NOFALLBACK_FORMAT_CLASS_CONTROL = new NoFallbackControl( + JAVACLASS); + + static final Control NOFALLBACK_FORMAT_DEFAULT_CONTROL = new NoFallbackControl( + listDefault); + + public NoFallbackControl(String format) { + super(); + listClass = new ArrayList(); + listClass.add(format); + super.format = Collections.unmodifiableList(listClass); + } + + public NoFallbackControl(List list) { + super(); + super.format = list; + } + + @Override + public Locale getFallbackLocale(String baseName, Locale locale) { + if (null == baseName || null == locale) { + throw new NullPointerException(); + } + return null; + } + } + + private static class SimpleControl extends Control { + public SimpleControl(String format) { + super(); + listClass = new ArrayList(); + listClass.add(format); + super.format = Collections.unmodifiableList(listClass); + } + } + + @SuppressWarnings("nls") + /** + * ResourceBundle.Control is a static utility class defines ResourceBundle + * load access methods, its default access order is as the same as before. + * However users can implement their own control. + * + * @since 1.6 + * @hide + */ + public static class Control { + static List listDefault = new ArrayList(); + + static List listClass = new ArrayList(); + + static List listProperties = new ArrayList(); + + static String JAVACLASS = "java.class"; + + static String JAVAPROPERTIES = "java.properties"; + + static { + listDefault.add(JAVACLASS); + listDefault.add(JAVAPROPERTIES); + listClass.add(JAVACLASS); + listProperties.add(JAVAPROPERTIES); + } + + /** + * a list defines default format + */ + public static final List FORMAT_DEFAULT = Collections + .unmodifiableList(listDefault); + + /** + * a list defines java class format + */ + public static final List FORMAT_CLASS = Collections + .unmodifiableList(listClass); + + /** + * a list defines property format + */ + public static final List FORMAT_PROPERTIES = Collections + .unmodifiableList(listProperties); + + /** + * a constant that indicates cache will not be used. + */ + public static final long TTL_DONT_CACHE = -1L; + + /** + * a constant that indicates cache will not be expired. + */ + public static final long TTL_NO_EXPIRATION_CONTROL = -2L; + + private static final Control FORMAT_PROPERTIES_CONTROL = new SimpleControl( + JAVAPROPERTIES); + + private static final Control FORMAT_CLASS_CONTROL = new SimpleControl( + JAVACLASS); + + private static final Control FORMAT_DEFAULT_CONTROL = new Control(); + + List format; + + /** + * default constructor + * + */ + protected Control() { + super(); + listClass = new ArrayList(); + listClass.add(JAVACLASS); + listClass.add(JAVAPROPERTIES); + format = Collections.unmodifiableList(listClass); + } + + /** + * Answers a control according to the given format list + * + * @param formats + * a format to use + * @return a control according to the given format list + */ + public static final Control getControl(List formats) { + switch (formats.size()) { + case 1: + if (formats.contains(JAVACLASS)) { + return FORMAT_CLASS_CONTROL; + } + if (formats.contains(JAVAPROPERTIES)) { + return FORMAT_PROPERTIES_CONTROL; + } + break; + case 2: + if (formats.equals(FORMAT_DEFAULT)) { + return FORMAT_DEFAULT_CONTROL; + } + break; + } + throw new IllegalArgumentException(); + } + + /** + * Answers a control according to the given format list whose fallback + * locale is null + * + * @param formats + * a format to use + * @return a control according to the given format list whose fallback + * locale is null + */ + public static final Control getNoFallbackControl(List formats) { + switch (formats.size()) { + case 1: + if (formats.contains(JAVACLASS)) { + return NoFallbackControl.NOFALLBACK_FORMAT_CLASS_CONTROL; + } + if (formats.contains(JAVAPROPERTIES)) { + return NoFallbackControl.NOFALLBACK_FORMAT_PROPERTIES_CONTROL; + } + break; + case 2: + if (formats.equals(FORMAT_DEFAULT)) { + return NoFallbackControl.NOFALLBACK_FORMAT_DEFAULT_CONTROL; + } + break; + } + throw new IllegalArgumentException(); + } + + /** + * Answers a list of candidate locales according to the base name and + * locale + * + * @param baseName + * the base name to use + * @param locale + * the locale + * @return the candidate locales according to the base name and locale + */ + public List getCandidateLocales(String baseName, Locale locale) { + if (null == baseName || null == locale) { + throw new NullPointerException(); + } + List retList = new ArrayList(); + String language = locale.getLanguage(); + String country = locale.getCountry(); + String variant = locale.getVariant(); + if (!EMPTY_STRING.equals(variant)) { + retList.add(new Locale(language, country, variant)); + } + if (!EMPTY_STRING.equals(country)) { + retList.add(new Locale(language, country)); + } + if (!EMPTY_STRING.equals(language)) { + retList.add(new Locale(language)); + } + retList.add(Locale.ROOT); + return retList; + } + + /** + * Answers a list of strings of formats according to the base name + * + * @param baseName + * the base name to use + * @return a list of strings of formats according to the base name + */ + public List getFormats(String baseName) { + if (null == baseName) { + throw new NullPointerException(); + } + return format; + } + + /** + * Answers a list of strings of locales according to the base name + * + * @param baseName + * the base name to use + * @return a list of strings of locales according to the base name + */ + public Locale getFallbackLocale(String baseName, Locale locale) { + if (null == baseName || null == locale) { + throw new NullPointerException(); + } + if (Locale.getDefault() != locale) { + return Locale.getDefault(); + } + return null; + } + + /** + * Answers a new ResourceBundle according to the give parameters + * + * @param baseName + * the base name to use + * @param locale + * the given locale + * @param format + * the format, default is "java.class" or "java.properities" + * @param loader + * the classloader to use + * @param reload + * if reload the resource + * @return a new ResourceBundle according to the give parameters + * @throws IllegalAccessException + * if can not access resources + * @throws InstantiationException + * if can not instante a resource class + * @throws IOException + * if other I/O exception happens + */ + public ResourceBundle newBundle(String baseName, Locale locale, + String format, ClassLoader loader, boolean reload) + throws IllegalAccessException, InstantiationException, + IOException { + if (null == format || null == loader) { + throw new NullPointerException(); + } + InputStream streams = null; + final String bundleName = toBundleName(baseName, locale); + final ClassLoader clsloader = loader; + ResourceBundle ret; + Class cls = null; + if (JAVACLASS == format) { + cls = AccessController + .doPrivileged(new PrivilegedAction>() { + public Class run() { + try { + return clsloader.loadClass(bundleName); + } catch (Exception e) { + return null; + } catch (NoClassDefFoundError e) { + return null; + } + } + }); + if (null == cls) { + return null; + } + try { + ResourceBundle bundle = (ResourceBundle) cls.newInstance(); + bundle.setLocale(locale); + return bundle; + } catch (NullPointerException e) { + return null; + } + } + if (JAVAPROPERTIES == format) { + final String resourceName = toResourceName(bundleName, + "properties"); + if (reload) { + URL url = null; + try { + url = loader.getResource(resourceName); + } catch (NullPointerException e) { + // do nothing + } + if (null != url) { + URLConnection con = url.openConnection(); + con.setUseCaches(false); + streams = con.getInputStream(); + } + } else { + try { + streams = AccessController + .doPrivileged(new PrivilegedAction() { + public InputStream run() { + return clsloader + .getResourceAsStream(resourceName); + } + }); + } catch (NullPointerException e) { + // do nothing + } + } + if (streams != null) { + try { + ret = new PropertyResourceBundle(new InputStreamReader(streams)); + ret.setLocale(locale); + streams.close(); + } catch (IOException e) { + return null; + } + return ret; + } + return null; + } + throw new IllegalArgumentException(); + } + + /** + * Answers the time to live of the ResourceBundle, default is + * TTL_NO_EXPIRATION_CONTROL + * + * @param baseName + * the base name to use + * @param locale + * the locale to use + * @return TTL_NO_EXPIRATION_CONTROL + */ + public long getTimeToLive(String baseName, Locale locale) { + if (null == baseName || null == locale) { + throw new NullPointerException(); + } + return TTL_NO_EXPIRATION_CONTROL; + } + + /** + * Answers if the ResourceBundle needs to reload + * + * @param baseName + * the base name of the ResourceBundle + * @param locale + * the locale of the ResourceBundle + * @param format + * the format to load + * @param loader + * the ClassLoader to load resource + * @param bundle + * the ResourceBundle + * @param loadTime + * the expired time + * @return if the ResourceBundle needs to reload + */ + public boolean needsReload(String baseName, Locale locale, + String format, ClassLoader loader, ResourceBundle bundle, + long loadTime) { + if (null == bundle) { + // FIXME what's the use of bundle? + throw new NullPointerException(); + } + String bundleName = toBundleName(baseName, locale); + String suffix = format; + if (JAVACLASS == format) { + suffix = "class"; + } + if (JAVAPROPERTIES == format) { + suffix = "properties"; + } + String urlname = toResourceName(bundleName, suffix); + URL url = loader.getResource(urlname); + if (null != url) { + String fileName = url.getFile(); + long lastModified = new File(fileName).lastModified(); + if (lastModified > loadTime) { + return true; + } + } + return false; + } + + /** + * a utility method to answer the name of a resource bundle according to + * the given base name and locale + * + * @param baseName + * the given base name + * @param locale + * the locale to use + * @return the name of a resource bundle according to the given base + * name and locale + */ + public String toBundleName(String baseName, Locale locale) { + final String emptyString = EMPTY_STRING; + final String preString = UNDER_SCORE; + final String underline = UNDER_SCORE; + if (null == baseName) { + throw new NullPointerException(); + } + StringBuilder ret = new StringBuilder(); + StringBuilder prefix = new StringBuilder(); + ret.append(baseName); + if (!locale.getLanguage().equals(emptyString)) { + ret.append(underline); + ret.append(locale.getLanguage()); + } else { + prefix.append(preString); + } + if (!locale.getCountry().equals(emptyString)) { + ret.append((CharSequence) prefix); + ret.append(underline); + ret.append(locale.getCountry()); + prefix = new StringBuilder(); + } else { + prefix.append(preString); + } + if (!locale.getVariant().equals(emptyString)) { + ret.append((CharSequence) prefix); + ret.append(underline); + ret.append(locale.getVariant()); + } + return ret.toString(); + } + + /** + * a utility method to answer the name of a resource according to the + * given bundleName and suffix + * + * @param bundleName + * the given bundle name + * @param suffix + * the suffix + * @return the name of a resource according to the given bundleName and + * suffix + */ + public final String toResourceName(String bundleName, String suffix) { + if (null == suffix) { + throw new NullPointerException(); + } + StringBuilder ret = new StringBuilder(bundleName.replace('.', '/')); + ret.append('.'); + ret.append(suffix); + return ret.toString(); + } } } diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/nls/messages.properties b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/nls/messages.properties index 88698809b..4b8ce5c84 100644 --- a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/nls/messages.properties +++ b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/nls/messages.properties @@ -18,11 +18,6 @@ luni.00=Connection has not been established yet luni.01=Could not make SSL Tunneling. Got response: {0} ({1}) luni.02=Hostname <{0}> was not verified luni.03=The enum constant {0}.{1} is missing -luni.04=this Map luni.05=Attempt to insert {0} element into collection with element type {1} luni.06=The string argument is null luni.07=The stream is corrupted -luni.08=Invalid Unicode sequence: expected format \\uxxxx -luni.09=Invalid Unicode sequence: illegal character -luni.0A=Index: {0}, Size: {1} -luni.0B=Array index out of range: {0} diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties b/libcore/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties index b6cbcef00..2c7d60550 100644 --- a/libcore/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties +++ b/libcore/luni/src/main/java/org/apache/harmony/luni/util/ExternalMessages.properties @@ -15,38 +15,13 @@ # External Messages for EN locale K0006=Negative index specified -K0007=attempt to write after finish -K0008=Cannot read version -K0009=Missing version string\: {0} -K000a=Entry is not named -K000b=Invalid attribute {0} -K000c=cannot resolve subclasses -K000d=Unknown attribute -K000e=Cannot add attributes to empty string -K0014=Unquoted {0} in suffix\: {1} -K0015=Unexpected {0} in fraction\: {1} -K0016=Unexpected {0} in {1} -K0017=Missing pattern before {0} in {1} -K0018=Missing exponent format {0} -K0019=Unterminated quote {0} -K001a=Missing grouping format {0} -K001b=Invalid exponent format {0} -K001c=Invalid pattern char {0} in {1} -K001d=Invalid argument number -K001e=Missing element format -K001f=Unknown element format -K0020=Unknown format -K002b=Unknown pattern character - '{0}' -K002c=Access denied {0} K002e=Offset out of bounds \: {0} K002f=Arguments out of bounds K0032=Address null or destination port out of range -K0033=Unknown socket type K0034=Packet address mismatch with connected address K0035=Zero or negative buffer size K0036=Invalid negative timeout K0037=Connection already established -K0038=No host name provided K0039=Attempted to join a non-multicast group K003a=Attempted to leave a non-multicast group K003c=TimeToLive out of bounds @@ -54,7 +29,6 @@ K003d=Socket is closed K003e=SOCKS connection failed\: {0} K003f=Unable to connect to SOCKS server\: {0} K0040=Invalid SOCKS client. -K0041=Socket implementation does not support SOCKS. K0042=Socket implementation factory already set K0044=The factory has already been set K0045=Attempted to set a negative SoLinger @@ -67,19 +41,11 @@ K004b=Attempt to set factory more than once. K004c=Package is sealed K004d=Does not support writing to the input stream K004e=Duplicate Factory -K004f=rounding necessary -K0050=wrong rounding mode K0051=scale value < than zero K0052=Array index out of range\: {0} -K0053=Package {0} already defined. K0055=String index out of range\: {0} -K0056=Already destroyed -K0057=Has threads K0058=size must be > 0 K0059=Stream is closed -# // BEGIN android-deleted -# // K005a=Mark has been invalidated. -# // END android-deleted K005b=BufferedReader is closed K005c=Invalid Mark. K005d=Writer is closed. @@ -90,9 +56,7 @@ K0062=Second byte at {0} does not match UTF8 Specification K0063=Third byte at {0} does not match UTF8 Specification K0064=Second or third byte at {0} does not match UTF8 Specification K0065=Input at {0} does not match UTF8 Specification -K0066=Entry already exists: {0} K0068=String is too long -K0069=File cannot compare to non File K006a=time must be positive K006b=Prefix must be at least 3 characters K006c=FileDescriptor is null @@ -102,11 +66,9 @@ K006f=invalid permission\: {0} K0070=InputStreamReader is closed. K0071=Error fetching SUID\: {0} K0072={0} computing SHA-1 / SUID -K0073=OutputStreamWriter is closed. K0074=Not connected K0075=InputStream is closed K0076=Pipe broken -K0077=Crc mismatch K0078=Pipe is closed K0079=Already connected K007a=Pipe already connected @@ -117,13 +79,6 @@ K0080=Reader is closed K0081=Mode must be one of "r" or "rw" K0083=StringReader is closed. K0084=can only instantiate one BootstrapClassLoader -K0086=Referenced reflect object is no longer valid -K0087=Referenced reflect object is no longer valid\: {0} -K0088=Incorrect end of BER tag -K0089=Unknown type\: {0} -K008a=Read {0} bytes trying to read {1} bytes from {2} -K008b=Position\: {0} -K008c=Invalid Base64 char\:{0} K008d=This protocol does not support input K008e=Does not support output K008f=This method does not support writing\: {0} @@ -139,20 +94,13 @@ K0098=Unable to log into server\: {0} K0099=Unable to configure data port K009a=Unable to store file K009b=Unable to set transfer type -K00a2=Parsing policy file\: {0}, expected quoted {1}, found unquoted\: {2} -K00a3=Parsing policy file\: {0}, found unexpected\: {1} K00a4=Content-Length underflow K00a5=Invalid parameter - {0} -K00a8=Parsing policy file\: {0}, invalid codesource URL\: {1} -K00ab=No active entry -K00ae=Size mismatch K00af=Invalid proxy port\: {0} K00b0=Proxy port out of range K00b1=Invalid port number K00b2=Content-Length exceeded K00b3=Unknown protocol\: {0} -K00b6=No entries -K00b7=File is closed K00c1=Illegal character K00cd=Failure to connect to SOCKS server. K00ce=Unable to connect to identd to verify user. @@ -168,65 +116,27 @@ K00d8=Protocol not found\: {0} K00d9=Callback object cannot be null K00da=Incompatible class (SUID)\: {0} but expected {1} K00dc=IllegalAccessException -K00e3=Could not create specified security manager\: {0} -K00e4=Key usage is critical and cannot be used for digital signature purposes. K00e5=month\: {0} K00e6=day of month\: {0} K00e7=day of week\: {0} K00e8=time\: {0} K00e9=DST offset\: {0} K00ea=era\: {0} -K00eb={0} failed verification of {1} -K00ec={0} has invalid digest for {1} in {2} K00ed={0} is not an interface K00ee={0} is not visible from class loader K00ef={0} appears more than once K00f0=non-public interfaces must be in the same package K00f1=not a proxy instance -K00f2=the methods named {0} must have the same return type K00f3=Timer was cancelled K00f5=Illegal delay to start the TimerTask K00f6=TimerTask is scheduled already K00f7=TimerTask is cancelled K00f8=day of week in month\: {0} -K00f9=min or max digit count too large -K00fa=min digits greater than max digits -K00fb=min or max digits negative K00fc=Jar entry not specified -K00fd=Invalid keystore -K00fe=Incorrect password -K0185=The alias already exists for a key entry. -K018f=Can't convert to BMPString \: {0} -K0190=No data to decode -K0191=Invalid size, must be a multiple of 64 from 512 to 1024 -K0193=An identity with this name already exists in this scope -K0194=An identity in the scope has the same public key -K0195=The existing public key and the one contained in the certificate do not match. -K0196=Certificate is missing K0199=Count out of range -K01a0=End of stream condition -K01a4=Already shutting down -K01a5=Illegal shutdown hook\: {0} -K01a6=Invalid filter -K01a7=Name too long: {0} -K01b3=Incorrect number of arguments -K01b4=Cannot convert {0} to {1} K01b6=Cannot find \!/ -K01c1=File is a Directory -K01c2=Cannot create\: {0} -K01c3=Unable to open\: {0} -K01c4=Invalid zip file\: {0} -K01c6=No Main-Class specified in manifest\: {0} -K01d1=Signers of '{0}' do not match signers of other classes in package -K01d2={1} - protected system package '{0}' -K01ec=key size must be a multiple of 8 bits -K01ed=key size must be at least 512 bits K01fe=Incomplete % sequence at\: {0} K01ff=Invalid % sequence ({0}) at\: {1} -K0220=UTFDataFormatException -K0222=No Manifest found in jar file\: {0} -K0300=Unsupported encoding -K0301=Not signed data K0302=Relative path K0303=Scheme-specific part expected K0304=Authority expected @@ -249,7 +159,6 @@ K0315=Socket is already bound K0316=SocketAddress {0} not supported K0317=Host is unresolved\: {0} K0318=SocketAddress is null -K0319=Exception in thread "{0}"\ K031a=URI is not absolute\: {0} K031b=URI is not hierarchical\: {0} K031c=Expected file scheme in URI\: {0} @@ -260,25 +169,19 @@ K0320=Socket is not connected K0321=Socket input is shutdown K0322=Not a supported ISO 4217 Currency Code\: {0} K0323=Not a supported ISO 3166 Country locale\: {0} -K0324=Needs dictionary K0325=Port out of range\: {0} K0326={0} at index {1}\: {2} K0327={0}\: {1} -K0328=Certificate not yet valid -K0329=Certificate expired K0330=interface name is null K0331=address is null K0332=Invalid IP Address is neither 4 or 16 bytes\: {0} K0333=Urgent data not supported K0334=Cannot set network interface with null K0335=No addresses associated with Interface -K0337=null type not allowed K0338=Address not associated with an interface - not set K0339=Invalid IP Address is neither 4 or 16 bytes K0340={0} incompatible with {1} K0342=Scheme expected -K0344=Not a valid {0}, subclass should override readResolve() -K0346=Unmatched braces in the pattern K0347=seek position is negative K0348=Format specifier '{0}' K0349=Conversion is '{0}' @@ -286,10 +189,8 @@ K034a=The flags are {0} K034b=url and proxy can not be null K034c=proxy should not be null K034d=method has not been implemented yet -K034e=Build rules empty K0351=format is null K0352=package is sealed -KA000=Line too long KA001=Argument must not be null KA002=Unshared read of back reference KA003=different mode already set @@ -301,7 +202,6 @@ KA008={0} is an illegal radix KA009=CharsetName is illegal KA00a=File is null KA00b=InputStream is null -KA00c=Readable is null KA00d=ReadableByteChannel is null KA00e=Radix {0} is less than Character.MIN_RADIX or greater than Character.MAX_RADIX KA00f=Socket output is shutdown @@ -321,10 +221,8 @@ KA022=Illegal Proxy.Type or SocketAddress argument KA023=Proxy is null or invalid type KA024=One of urls is null KA025=Method has not been implemented -KA026=JAR entry {0} not found in {1} KA027=Inputstream of the JarURLConnection has been closed KA028=Cannot set protocol version when stream in use -KA029=Can't find resource for bundle {0}, key {1} KA030=Write end dead K0031=Length out of bounds \: {0} K0032=Source size {0} does not fit into destination diff --git a/libcore/luni/src/test/java/tests/api/java/util/PropertiesTest.java b/libcore/luni/src/test/java/tests/api/java/util/PropertiesTest.java index 84a81d2ad..d1d4c6739 100644 --- a/libcore/luni/src/test/java/tests/api/java/util/PropertiesTest.java +++ b/libcore/luni/src/test/java/tests/api/java/util/PropertiesTest.java @@ -17,24 +17,29 @@ package tests.api.java.util; -import dalvik.annotation.KnownFailure; -import dalvik.annotation.TestTargetNew; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.StringReader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Enumeration; import java.util.InvalidPropertiesFormatException; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; import java.util.Properties; +import java.util.Scanner; +import java.util.Set; import tests.support.resource.Support_Resources; -@TestTargetClass(Properties.class) public class PropertiesTest extends junit.framework.TestCase { Properties tProps; @@ -44,76 +49,76 @@ public class PropertiesTest extends junit.framework.TestCase { /** * @tests java.util.Properties#Properties() */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "Properties", - args = {} - ) public void test_Constructor() { + // Test for method java.util.Properties() Properties p = new Properties(); // do something to avoid getting a variable unused warning p.clear(); + assertTrue("Created incorrect Properties", true); + } + + public void test_loadLjava_io_InputStream_NPE() throws Exception { + Properties p = new Properties(); + try { + p.load((InputStream) null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // Expected + } + } + + public void test_loadsave() throws Exception{ + Properties p = new Properties(); + try { + p.load((InputStream) null); + fail("should throw NPE"); + } catch (NullPointerException npe) { + // expected + } } /** * @tests java.util.Properties#Properties(java.util.Properties) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "Properties", - args = {java.util.Properties.class} - ) public void test_ConstructorLjava_util_Properties() { - if (System.getProperty("java.vendor") != null) { - Properties p = new Properties(System.getProperties()); - assertNotNull("failed to construct correct properties", p - .getProperty("java.vendor")); + Properties systemProperties = System.getProperties(); + Properties properties = new Properties(systemProperties); + Enumeration propertyNames = systemProperties.propertyNames(); + String propertyName = null; + while (propertyNames.hasMoreElements()) { + propertyName = (String) propertyNames.nextElement(); + assertEquals("failed to construct correct properties", + systemProperties.get(propertyName), properties + .getProperty(propertyName)); } } /** * @tests java.util.Properties#getProperty(java.lang.String) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "Verifies positive case.", - method = "getProperty", - args = {java.lang.String.class} - ) public void test_getPropertyLjava_lang_String() { + // Test for method java.lang.String + // java.util.Properties.getProperty(java.lang.String) assertEquals("Did not retrieve property", "this is a test property", - tProps.getProperty("test.prop")); + ((String) tProps.getProperty("test.prop"))); } /** * @tests java.util.Properties#getProperty(java.lang.String, * java.lang.String) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "getProperty", - args = {java.lang.String.class, java.lang.String.class} - ) public void test_getPropertyLjava_lang_StringLjava_lang_String() { + // Test for method java.lang.String + // java.util.Properties.getProperty(java.lang.String, java.lang.String) assertEquals("Did not retrieve property", "this is a test property", - tProps.getProperty("test.prop", "Blarg")); - assertEquals("Did not return default value", "Gabba", tProps - .getProperty("notInThere.prop", "Gabba")); - assertNull(tProps.getProperty("", null)); + ((String) tProps.getProperty("test.prop", "Blarg"))); + assertEquals("Did not return default value", "Gabba", ((String) tProps + .getProperty("notInThere.prop", "Gabba"))); } /** * @tests java.util.Properties#getProperty(java.lang.String) */ - @TestTargetNew( - level = TestLevel.PARTIAL_COMPLETE, - notes = "Regression test.", - method = "getProperty", - args = {java.lang.String.class} - ) public void test_getPropertyLjava_lang_String2() { // regression test for HARMONY-3518 MyProperties props = new MyProperties(); @@ -124,16 +129,10 @@ public class PropertiesTest extends junit.framework.TestCase { * @tests java.util.Properties#getProperty(java.lang.String, * java.lang.String) */ - @TestTargetNew( - level = TestLevel.PARTIAL_COMPLETE, - notes = "Regression test.", - method = "getProperty", - args = {java.lang.String.class, java.lang.String.class} - ) public void test_getPropertyLjava_lang_StringLjava_lang_String2() { // regression test for HARMONY-3518 MyProperties props = new MyProperties(); - assertEquals(props.getProperty("key", "defaultValue"), "defaultValue"); + assertEquals("defaultValue", props.getProperty("key", "defaultValue")); } // regression testing for HARMONY-3518 @@ -146,80 +145,192 @@ public class PropertiesTest extends junit.framework.TestCase { /** * @tests java.util.Properties#list(java.io.PrintStream) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "list", - args = {java.io.PrintStream.class} - ) public void test_listLjava_io_PrintStream() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); Properties myProps = new Properties(); - String propList; myProps.setProperty("Abba", "Cadabra"); myProps.setProperty("Open", "Sesame"); + myProps.setProperty("LongProperty", + "a long long long long long long long property"); myProps.list(ps); ps.flush(); - propList = baos.toString(); - assertTrue("Property list innacurate", (propList - .indexOf("Abba=Cadabra") >= 0) - && (propList.indexOf("Open=Sesame") >= 0)); + String propList = baos.toString(); + assertTrue("Property list innacurate", + propList.indexOf("Abba=Cadabra") >= 0); + assertTrue("Property list innacurate", + propList.indexOf("Open=Sesame") >= 0); + assertTrue("property list do not conatins \"...\"", propList + .indexOf("...") != -1); + + ps = null; + try { + myProps.list(ps); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } } /** * @tests java.util.Properties#list(java.io.PrintWriter) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "list", - args = {java.io.PrintWriter.class} - ) public void test_listLjava_io_PrintWriter() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter pw = new PrintWriter(baos); Properties myProps = new Properties(); - String propList; myProps.setProperty("Abba", "Cadabra"); myProps.setProperty("Open", "Sesame"); + myProps.setProperty("LongProperty", + "a long long long long long long long property"); myProps.list(pw); pw.flush(); - propList = baos.toString(); - assertTrue("Property list innacurate", (propList - .indexOf("Abba=Cadabra") >= 0) - && (propList.indexOf("Open=Sesame") >= 0)); + String propList = baos.toString(); + assertTrue("Property list innacurate", + propList.indexOf("Abba=Cadabra") >= 0); + assertTrue("Property list innacurate", + propList.indexOf("Open=Sesame") >= 0); + pw = null; + try { + myProps.list(pw); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } } /** - * @throws IOException * @tests java.util.Properties#load(java.io.InputStream) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "load", - args = {java.io.InputStream.class} - ) - public void test_loadLjava_io_InputStream() throws IOException { - Properties prop = new Properties(); - InputStream is = new ByteArrayInputStream(writeProperties()); - prop.load(is); - is.close(); - + public void test_loadLjava_io_InputStream() { + // Test for method void java.util.Properties.load(java.io.InputStream) + Properties prop = null; + try { + InputStream is; + prop = new Properties(); + prop.load(is = new ByteArrayInputStream(writeProperties())); + is.close(); + } catch (Exception e) { + fail("Exception during load test : " + e.getMessage()); + } assertEquals("Failed to load correct properties", "harmony.tests", prop .getProperty("test.pkg")); assertNull("Load failed to parse incorrectly", prop .getProperty("commented.entry")); prop = new Properties(); - prop.load(new ByteArrayInputStream("=".getBytes())); + try { + prop.load(new ByteArrayInputStream("=".getBytes())); + } catch (IOException e) { + // expected + } assertTrue("Failed to add empty key", prop.get("").equals("")); prop = new Properties(); - prop.load(new ByteArrayInputStream(" = ".getBytes())); + try { + prop.load(new ByteArrayInputStream(" = ".getBytes())); + } catch (IOException e) { + // expected + } assertTrue("Failed to add empty key2", prop.get("").equals("")); + prop = new Properties(); + try { + prop.load(new ByteArrayInputStream(" a= b".getBytes())); + } catch (IOException e) { + // expected + } + assertEquals("Failed to ignore whitespace", "b", prop.get("a")); + + prop = new Properties(); + try { + prop.load(new ByteArrayInputStream(" a b".getBytes())); + } catch (IOException e) { + // expected + } + assertEquals("Failed to interpret whitespace as =", "b", prop.get("a")); + + prop = new Properties(); + try { + prop.load(new ByteArrayInputStream("#\u008d\u00d2\na=\u008d\u00d3" + .getBytes("ISO8859_1"))); + } catch (IOException e) { + // expected + } + assertEquals("Failed to parse chars >= 0x80", "\u008d\u00d3", prop + .get("a")); + + prop = new Properties(); + try { + prop.load(new ByteArrayInputStream( + "#properties file\r\nfred=1\r\n#last comment" + .getBytes("ISO8859_1"))); + } catch (IOException e) { + // expected + } catch (IndexOutOfBoundsException e) { + fail("IndexOutOfBoundsException when last line is a comment with no line terminator"); + } + assertEquals("Failed to load when last line contains a comment", "1", + prop.get("fred")); + } + + /** + * @tests java.util.Properties#load(java.io.InputStream) + */ + public void test_loadLjava_io_InputStream_subtest0() { + try { + InputStream is = Support_Resources + .getStream("hyts_PropertiesTest.properties"); + Properties props = new Properties(); + props.load(is); + is.close(); + assertEquals("1", "\n \t \f", props.getProperty(" \r")); + assertEquals("2", "a", props.getProperty("a")); + assertEquals("3", "bb as,dn ", props.getProperty("b")); + assertEquals("4", ":: cu", props.getProperty("c\r \t\nu")); + assertEquals("5", "bu", props.getProperty("bu")); + assertEquals("6", "d\r\ne=e", props.getProperty("d")); + assertEquals("7", "fff", props.getProperty("f")); + assertEquals("8", "g", props.getProperty("g")); + assertEquals("9", "", props.getProperty("h h")); + assertEquals("10", "i=i", props.getProperty(" ")); + assertEquals("11", " j", props.getProperty("j")); + assertEquals("12", " c", props.getProperty("space")); + assertEquals("13", "\\", props.getProperty("dblbackslash")); + } catch (IOException e) { + fail("Unexpected: " + e); + } + } + + /** + * @throws IOException + * @tests java.util.Properties#load(java.io.Reader) + * @since 1.6 + */ + public void test_loadLjava_io_Reader() throws IOException { + Properties prop = null; + try { + InputStream is; + prop = new Properties(); + is = new ByteArrayInputStream(writeProperties()); + prop.load(new InputStreamReader(is)); + is.close(); + } catch (Exception e) { + fail("Exception during load test : " + e.getMessage()); + } + assertEquals("Failed to load correct properties", "harmony.tests", prop + .getProperty("test.pkg")); + assertNull("Load failed to parse incorrectly", prop + .getProperty("commented.entry")); + + prop = new Properties(); + prop.load(new ByteArrayInputStream("=".getBytes())); + assertEquals("Failed to add empty key", "", prop.get("")); + + prop = new Properties(); + prop.load(new ByteArrayInputStream(" = ".getBytes())); + assertEquals("Failed to add empty key2", "", prop.get("")); + prop = new Properties(); prop.load(new ByteArrayInputStream(" a= b".getBytes())); assertEquals("Failed to ignore whitespace", "b", prop.get("a")); @@ -229,42 +340,102 @@ public class PropertiesTest extends junit.framework.TestCase { assertEquals("Failed to interpret whitespace as =", "b", prop.get("a")); prop = new Properties(); - prop.load(new ByteArrayInputStream("#\u008d\u00d2\na=\u008d\u00d3" - .getBytes("ISO8859_1"))); - assertEquals("Failed to parse chars >= 0x80", "\u008d\u00d3", prop - .get("a")); + prop.load(new ByteArrayInputStream("#comment\na=value" + .getBytes("UTF-8"))); + assertEquals("value", prop.getProperty("a")); prop = new Properties(); - prop.load(new ByteArrayInputStream( - "#properties file\r\nfred=1\r\n#last comment" - .getBytes("ISO8859_1"))); + prop.load(new InputStreamReader(new ByteArrayInputStream( + "#\u008d\u00d2\na=\u008d\u00d3".getBytes("UTF-8")))); + try { + prop + .load(new InputStreamReader(new ByteArrayInputStream( + "#\u008d\u00d2\na=\\\\u008d\\\\\\uu00d3" + .getBytes("UTF-8")))); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + prop = new Properties(); + try { + prop.load(new InputStreamReader(new ByteArrayInputStream( + "#properties file\r\nfred=1\r\n#last comment" + .getBytes("ISO8859_1")))); + } catch (IndexOutOfBoundsException e) { + fail("IndexOutOfBoundsException when last line is a comment with no line terminator"); + } assertEquals("Failed to load when last line contains a comment", "1", prop.get("fred")); - ByteArrayInputStream bais = new ByteArrayInputStream(new byte[]{'\\', 'u', 'x', 'x', 'x', 'x'}); + // Regression tests for HARMONY-5414 + prop = new Properties(); + prop.load(new ByteArrayInputStream("a=\\u1234z".getBytes())); + + prop = new Properties(); try { - prop.load(bais); - fail("IllegalArgumentException expected"); + prop.load(new ByteArrayInputStream("a=\\u123".getBytes())); + fail("should throw IllegalArgumentException"); } catch (IllegalArgumentException e) { - //expected + // Expected + } + + prop = new Properties(); + try { + prop.load(new ByteArrayInputStream("a=\\u123z".getBytes())); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + // Expected } + + prop = new Properties(); + Properties expected = new Properties(); + expected.put("a", "\u0000"); + prop.load(new ByteArrayInputStream("a=\\".getBytes())); + assertEquals("Failed to read trailing slash value", expected, prop); + + prop = new Properties(); + expected = new Properties(); + expected.put("a", "\u1234\u0000"); + prop.load(new ByteArrayInputStream("a=\\u1234\\".getBytes())); + assertEquals("Failed to read trailing slash value #2", expected, prop); + + prop = new Properties(); + expected = new Properties(); + expected.put("a", "q"); + prop.load(new ByteArrayInputStream("a=\\q".getBytes())); + assertEquals("Failed to read slash value #3", expected, prop); + } + + /** + * @tests java.util.Properties#load(java.io.InputStream) + */ + public void test_loadLjava_io_InputStream_Special() throws IOException { + // Test for method void java.util.Properties.load(java.io.InputStream) + Properties prop = null; + prop = new Properties(); + prop.load(new ByteArrayInputStream("=".getBytes())); + assertTrue("Failed to add empty key", prop.get("").equals("")); + + prop = new Properties(); + prop.load(new ByteArrayInputStream("=\r\n".getBytes())); + assertTrue("Failed to add empty key", prop.get("").equals("")); + + prop = new Properties(); + prop.load(new ByteArrayInputStream("=\n\r".getBytes())); + assertTrue("Failed to add empty key", prop.get("").equals("")); } /** * @throws IOException - * @tests java.util.Properties#load(java.io.InputStream) + * @tests java.util.Properties#load(java.io.Reader) + * @since 1.6 */ - @TestTargetNew( - level = TestLevel.PARTIAL_COMPLETE, - notes = "Doesn't verify IOException, IllegalArgumentException.", - method = "load", - args = {java.io.InputStream.class} - ) - public void test_loadLjava_io_InputStream_subtest0() throws IOException { + public void test_loadLjava_io_Reader_subtest0() throws IOException { InputStream is = Support_Resources .getStream("hyts_PropertiesTest.properties"); Properties props = new Properties(); - props.load(is); + props.load(new InputStreamReader(is)); is.close(); assertEquals("1", "\n \t \f", props.getProperty(" \r")); assertEquals("2", "a", props.getProperty("a")); @@ -282,36 +453,240 @@ public class PropertiesTest extends junit.framework.TestCase { } /** - * @throws IOException + * @tests java.util.Properties#propertyNames() + */ + public void test_propertyNames() { + Properties myPro = new Properties(tProps); + Enumeration names = myPro.propertyNames(); + int i = 0; + while (names.hasMoreElements()) { + ++i; + String p = (String) names.nextElement(); + assertTrue("Incorrect names returned", p.equals("test.prop") + || p.equals("bogus.prop")); + } + } + + public void test_propertyNames_sequence() { + Properties parent = new Properties(); + parent.setProperty("parent.a.key", "parent.a.value"); + parent.setProperty("parent.b.key", "parent.b.value"); + + Enumeration names = parent.propertyNames(); + assertEquals("parent.a.key", names.nextElement()); + assertEquals("parent.b.key", names.nextElement()); + assertFalse(names.hasMoreElements()); + + Properties current = new Properties(parent); + current.setProperty("current.a.key", "current.a.value"); + current.setProperty("current.b.key", "current.b.value"); + + names = current.propertyNames(); + assertEquals("parent.a.key", names.nextElement()); + assertEquals("current.b.key", names.nextElement()); + assertEquals("parent.b.key", names.nextElement()); + assertEquals("current.a.key", names.nextElement()); + assertFalse(names.hasMoreElements()); + + Properties child = new Properties(current); + child.setProperty("child.a.key", "child.a.value"); + child.setProperty("child.b.key", "child.b.value"); + + names = child.propertyNames(); + assertEquals("parent.a.key", names.nextElement()); + assertEquals("child.b.key", names.nextElement()); + assertEquals("current.b.key", names.nextElement()); + assertEquals("parent.b.key", names.nextElement()); + assertEquals("child.a.key", names.nextElement()); + assertEquals("current.a.key", names.nextElement()); + assertFalse(names.hasMoreElements()); + } + + /** + * @tests {@link java.util.Properties#stringPropertyNames()} + * @since 1.6 + */ + public void test_stringPropertyNames() { + Set set = tProps.stringPropertyNames(); + assertEquals(2, set.size()); + assertTrue(set.contains("test.prop")); + assertTrue(set.contains("bogus.prop")); + assertNotSame(set, tProps.stringPropertyNames()); + + set = new Properties().stringPropertyNames(); + assertEquals(0, set.size()); + + set = new Properties(System.getProperties()).stringPropertyNames(); + assertTrue(set.size() > 0); + + tProps = new Properties(tProps); + tProps.put("test.prop", "anotherValue"); + tProps.put("3rdKey", "3rdValue"); + set = tProps.stringPropertyNames(); + assertEquals(3, set.size()); + assertTrue(set.contains("test.prop")); + assertTrue(set.contains("bogus.prop")); + assertTrue(set.contains("3rdKey")); + + tProps.put(String.class, "valueOfNonStringKey"); + set = tProps.stringPropertyNames(); + assertEquals(3, set.size()); + assertTrue(set.contains("test.prop")); + assertTrue(set.contains("bogus.prop")); + assertTrue(set.contains("3rdKey")); + + tProps.put("4thKey", "4thValue"); + assertEquals(4, tProps.size()); + assertEquals(3, set.size()); + + try { + set.add("another"); + fail("Should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + } + + /** + * @tests {@link java.util.Properties#stringPropertyNames()} + * @since 1.6 + */ + public void test_stringPropertyNames_scenario1() { + String[] keys = new String[] { "key1", "key2", "key3" }; + String[] values = new String[] { "value1", "value2", "value3" }; + List keyList = Arrays.asList(keys); + + Properties properties = new Properties(); + for (int index = 0; index < keys.length; index++) { + properties.setProperty(keys[index], values[index]); + } + + properties = new Properties(properties); + Set nameSet = properties.stringPropertyNames(); + assertEquals(keys.length, nameSet.size()); + Iterator iterator = nameSet.iterator(); + while (iterator.hasNext()) { + assertTrue(keyList.contains(iterator.next())); + } + + Enumeration nameEnum = properties.propertyNames(); + int count = 0; + while (nameEnum.hasMoreElements()) { + count++; + assertTrue(keyList.contains(nameEnum.nextElement())); + } + assertEquals(keys.length, count); + + properties = new Properties(properties); + nameSet = properties.stringPropertyNames(); + assertEquals(keys.length, nameSet.size()); + iterator = nameSet.iterator(); + while (iterator.hasNext()) { + assertTrue(keyList.contains(iterator.next())); + } + + nameEnum = properties.propertyNames(); + count = 0; + while (nameEnum.hasMoreElements()) { + count++; + assertTrue(keyList.contains(nameEnum.nextElement())); + } + assertEquals(keys.length, count); + } + + /** + * @tests {@link java.util.Properties#stringPropertyNames()} + * @since 1.6 + */ + public void test_stringPropertyNames_scenario2() { + String[] defaultKeys = new String[] { "defaultKey1", "defaultKey2", + "defaultKey3", "defaultKey4", "defaultKey5", "defaultKey6" }; + String[] defaultValues = new String[] { "defaultValue1", + "defaultValue2", "defaultValue3", "defaultValue4", + "defaultValue5", "defaultValue6" }; + List keyList = new ArrayList(); + Properties defaults = new Properties(); + for (int index = 0; index < 3; index++) { + defaults.setProperty(defaultKeys[index], defaultValues[index]); + keyList.add(defaultKeys[index]); + } + + String[] keys = new String[] { "key1", "key2", "key3" }; + String[] values = new String[] { "value1", "value2", "value3" }; + Properties properties = new Properties(defaults); + for (int index = 0; index < keys.length; index++) { + properties.setProperty(keys[index], values[index]); + keyList.add(keys[index]); + } + + Set nameSet = properties.stringPropertyNames(); + assertEquals(keyList.size(), nameSet.size()); + Iterator iterator = nameSet.iterator(); + while (iterator.hasNext()) { + assertTrue(keyList.contains(iterator.next())); + } + + Enumeration nameEnum = properties.propertyNames(); + int count = 0; + while (nameEnum.hasMoreElements()) { + count++; + assertTrue(keyList.contains(nameEnum.nextElement())); + } + assertEquals(keyList.size(), count); + + for (int index = 3; index < defaultKeys.length; index++) { + defaults.setProperty(defaultKeys[index], defaultValues[index]); + keyList.add(defaultKeys[index]); + } + + nameSet = properties.stringPropertyNames(); + assertEquals(keyList.size(), nameSet.size()); + iterator = nameSet.iterator(); + while (iterator.hasNext()) { + assertTrue(keyList.contains(iterator.next())); + } + + nameEnum = properties.propertyNames(); + count = 0; + while (nameEnum.hasMoreElements()) { + count++; + assertTrue(keyList.contains(nameEnum.nextElement())); + } + assertEquals(keyList.size(), count); + } + + /** * @tests java.util.Properties#save(java.io.OutputStream, java.lang.String) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "save", - args = {java.io.OutputStream.class, java.lang.String.class} - ) - public void test_saveLjava_io_OutputStreamLjava_lang_String() - throws IOException { + public void test_saveLjava_io_OutputStreamLjava_lang_String() { + // Test for method void java.util.Properties.save(java.io.OutputStream, + // java.lang.String) Properties myProps = new Properties(); + Properties myProps2 = new Properties(); + myProps.setProperty("Property A", "aye"); myProps.setProperty("Property B", "bee"); myProps.setProperty("Property C", "see"); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - myProps.save(out, "A Header"); - out.close(); - - Properties myProps2 = new Properties(); - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - myProps2.load(in); - in.close(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + myProps.save(out, "A Header"); + out.close(); + ByteArrayInputStream in = new ByteArrayInputStream(out + .toByteArray()); + myProps2.load(in); + in.close(); + } catch (IOException ioe) { + fail("IOException occurred reading/writing file : " + + ioe.getMessage()); + } Enumeration e = myProps.propertyNames(); + String nextKey; while (e.hasMoreElements()) { - String nextKey = (String) e.nextElement(); - assertTrue("Stored property list not equal to original", myProps2 - .getProperty(nextKey).equals(myProps.getProperty(nextKey))); + nextKey = (String) e.nextElement(); + assertEquals("Stored property list not equal to original", myProps + .getProperty(nextKey), myProps2.getProperty(nextKey)); } } @@ -319,13 +694,9 @@ public class PropertiesTest extends junit.framework.TestCase { * @tests java.util.Properties#setProperty(java.lang.String, * java.lang.String) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "setProperty", - args = {java.lang.String.class, java.lang.String.class} - ) public void test_setPropertyLjava_lang_StringLjava_lang_String() { + // Test for method java.lang.Object + // java.util.Properties.setProperty(java.lang.String, java.lang.String) Properties myProps = new Properties(); myProps.setProperty("Yoink", "Yabba"); assertEquals("Failed to set property", "Yabba", myProps @@ -336,93 +707,132 @@ public class PropertiesTest extends junit.framework.TestCase { } /** - * @throws IOException * @tests java.util.Properties#store(java.io.OutputStream, java.lang.String) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "store", - args = {java.io.OutputStream.class, java.lang.String.class} - ) - public void test_storeLjava_io_OutputStreamLjava_lang_String() - throws IOException { + public void test_storeLjava_io_OutputStreamLjava_lang_String() { + // Test for method void java.util.Properties.store(java.io.OutputStream, + // java.lang.String) Properties myProps = new Properties(); + Properties myProps2 = new Properties(); + Enumeration e; + String nextKey; + myProps.put("Property A", " aye\\\f\t\n\r\b"); myProps.put("Property B", "b ee#!=:"); myProps.put("Property C", "see"); - Properties myProps2 = new Properties(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - myProps.store(out, "A Header"); - myProps.store(out, null); - out.close(); - - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - myProps2.load(in); - in.close(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + myProps.store(out, "A Header"); + out.close(); + ByteArrayInputStream in = new ByteArrayInputStream(out + .toByteArray()); + myProps2.load(in); + in.close(); + } catch (IOException ioe) { + fail("IOException occurred reading/writing file : " + + ioe.getMessage()); + } - Enumeration e = myProps.propertyNames(); + e = myProps.propertyNames(); while (e.hasMoreElements()) { - String nextKey = (String) e.nextElement(); + nextKey = (String) e.nextElement(); assertTrue("Stored property list not equal to original", myProps2 .getProperty(nextKey).equals(myProps.getProperty(nextKey))); } - - try { - myProps.store(null, "String"); - fail("NullPointerException expected"); - } catch (NullPointerException ee){ - //expected - } + } /** * @throws IOException - * @tests java.util.Properties#loadFromXML(java.io.InputStream) + * @tests java.util.Properties#store(java.io.Writer, java.lang.String) + * @since 1.6 */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "loadFromXML", - args = {java.io.InputStream.class} - ) - public void test_loadFromXMLLjava_io_InputStream() throws IOException { + public void test_storeLjava_io_WriterLjava_lang_String() throws IOException { Properties myProps = new Properties(); + Properties myProps2 = new Properties(); + myProps.put("Property A", " aye\\\f\t\n\r\b"); myProps.put("Property B", "b ee#!=:"); myProps.put("Property C", "see"); - Properties myProps2 = new Properties(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - myProps.storeToXML(out, "A Header"); + myProps.store(new OutputStreamWriter(out), "A Header"); + Scanner scanner = new Scanner(out.toString()); + assertTrue(scanner.nextLine().startsWith("#A Header")); + assertTrue(scanner.nextLine().startsWith("#")); out.close(); - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + myProps2.load(in); + in.close(); + + Enumeration e = myProps.propertyNames(); + String nextKey; + while (e.hasMoreElements()) { + nextKey = (String) e.nextElement(); + assertTrue("Stored property list not equal to original", myProps2 + .getProperty(nextKey).equals(myProps.getProperty(nextKey))); + } + try { - myProps2.loadFromXML(in); - fail("InvalidPropertiesFormatException expected"); - } catch (InvalidPropertiesFormatException e) { - //expected + myProps.store((Writer) null, "some comments"); + fail("Should throw NullPointerException"); + } catch (NullPointerException e1) { + // expected } - in.close(); - - - Properties prop = new Properties(); - InputStream is = new ByteArrayInputStream(writePropertiesXML("UTF-8")); - prop.loadFromXML(is); - is.close(); + myProps.put(String.class, "wrong type"); + try { + myProps.store(new OutputStreamWriter(new ByteArrayOutputStream()), + "some comments"); + fail("Should throw ClassCastException"); + } catch (ClassCastException e1) { + // expected + } + myProps.remove(String.class); + myProps.store(new OutputStreamWriter(new ByteArrayOutputStream()), + "some comments"); + // it is OK + myProps.put("wrong type", String.class); + try { + myProps.store(new OutputStreamWriter(new ByteArrayOutputStream()), + "some comments"); + fail("Should throw ClassCastException"); + } catch (ClassCastException e1) { + // expected + } + } + + /** + * @tests java.util.Properties#loadFromXML(java.io.InputStream) + */ + public void test_loadFromXMLLjava_io_InputStream() throws Exception { + // Test for method void + // java.util.Properties.loadFromXML(java.io.InputStream) + Properties prop = null; + try { + InputStream is; + prop = new Properties(); + prop.loadFromXML(is = new ByteArrayInputStream( + writePropertiesXMLUTF_8())); + is.close(); + } catch (Exception e) { + fail("Exception during load test : " + e.getMessage()); + } assertEquals("Failed to load correct properties", "value3", prop .getProperty("key3")); assertEquals("Failed to load correct properties", "value1", prop .getProperty("key1")); - prop = new Properties(); - is = new ByteArrayInputStream(writePropertiesXML("ISO-8859-1")); - prop.loadFromXML(is); - is.close(); - + try { + InputStream is; + prop = new Properties(); + prop.loadFromXML(is = new ByteArrayInputStream( + writePropertiesXMLISO_8859_1())); + is.close(); + } catch (Exception e) { + fail("Exception during load test : " + e.getMessage()); + } assertEquals("Failed to load correct properties", "value2", prop .getProperty("key2")); assertEquals("Failed to load correct properties", "value1", prop @@ -430,26 +840,26 @@ public class PropertiesTest extends junit.framework.TestCase { try { prop.loadFromXML(null); - fail("NullPointerException expected"); + fail("should throw NullPointerException"); } catch (NullPointerException e) { - //expected + // expected } } /** - * @throws IOException * @tests java.util.Properties#storeToXML(java.io.OutputStream, * java.lang.String, java.lang.String) */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "storeToXML", - args = {java.io.OutputStream.class, java.lang.String.class, java.lang.String.class} - ) public void test_storeToXMLLjava_io_OutputStreamLjava_lang_StringLjava_lang_String() - throws IOException { + throws Exception { + // Test for method void + // java.util.Properties.storeToXML(java.io.OutputStream, + // java.lang.String, java.lang.String) Properties myProps = new Properties(); + Properties myProps2 = new Properties(); + Enumeration e; + String nextKey; + myProps.setProperty("key1", "value1"); myProps.setProperty("key2", "value2"); myProps.setProperty("key3", "value3"); @@ -465,126 +875,153 @@ public class PropertiesTest extends junit.framework.TestCase { myProps.setProperty("&key13<", "&&value13&"); - // store in UTF-8 encoding - ByteArrayOutputStream out = new ByteArrayOutputStream(); - myProps.storeToXML(out, "comment"); - out.close(); - - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - Properties myProps2 = new Properties(); - myProps2.loadFromXML(in); - in.close(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); - Enumeration e = myProps.propertyNames(); - while (e.hasMoreElements()) { - String nextKey = (String) e.nextElement(); - assertTrue("Stored property list not equal to original", myProps2 - .getProperty(nextKey).equals(myProps.getProperty(nextKey))); + // store in UTF-8 encoding + myProps.storeToXML(out, "comment"); + out.close(); + ByteArrayInputStream in = new ByteArrayInputStream(out + .toByteArray()); + myProps2.loadFromXML(in); + in.close(); + } catch (InvalidPropertiesFormatException ipfe) { + fail("InvalidPropertiesFormatException occurred reading file: " + + ipfe.getMessage()); + } catch (IOException ioe) { + fail("IOException occurred reading/writing file : " + + ioe.getMessage()); } - // store in ISO-8859-1 encoding - out = new ByteArrayOutputStream(); - myProps.storeToXML(out, "comment", "ISO-8859-1"); - out.close(); - - in = new ByteArrayInputStream(out.toByteArray()); - myProps2 = new Properties(); - myProps2.loadFromXML(in); - in.close(); - e = myProps.propertyNames(); while (e.hasMoreElements()) { - String nextKey = (String) e.nextElement(); + nextKey = (String) e.nextElement(); assertTrue("Stored property list not equal to original", myProps2 .getProperty(nextKey).equals(myProps.getProperty(nextKey))); } - out = new ByteArrayOutputStream(); - myProps.storeToXML(out, "comment", "ISO-8859-1"); - myProps.storeToXML(out, null, "ISO-8859-1"); - out.close(); - - try { - myProps.storeToXML(out, "comment", null); - fail("NulPointerException expected"); - } catch (NullPointerException ee) { - //expected - } - try { - myProps.storeToXML(null, "comment", "ISO-8859-1"); - fail("NulPointerException expected"); - } catch (NullPointerException ee) { - //expected + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + // store in ISO-8859-1 encoding + myProps.storeToXML(out, "comment", "ISO-8859-1"); + out.close(); + ByteArrayInputStream in = new ByteArrayInputStream(out + .toByteArray()); + myProps2 = new Properties(); + myProps2.loadFromXML(in); + in.close(); + } catch (InvalidPropertiesFormatException ipfe) { + fail("InvalidPropertiesFormatException occurred reading file: " + + ipfe.getMessage()); + } catch (IOException ioe) { + fail("IOException occurred reading/writing file : " + + ioe.getMessage()); } - } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "storeToXML", - args = {java.io.OutputStream.class, java.lang.String.class} - ) - public void test_storeToXMLLjava_io_OutputStreamLjava_lang_String() - throws IOException { - Properties myProps = new Properties(); - myProps.put("Property A", "value 1"); - myProps.put("Property B", "value 2"); - myProps.put("Property C", "value 3"); - - Properties myProps2 = new Properties(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - myProps.storeToXML(out, "A Header"); - out.close(); - - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - myProps2.loadFromXML(in); - in.close(); - - Enumeration e = myProps.propertyNames(); + e = myProps.propertyNames(); while (e.hasMoreElements()) { - String nextKey = (String) e.nextElement(); + nextKey = (String) e.nextElement(); assertTrue("Stored property list not equal to original", myProps2 .getProperty(nextKey).equals(myProps.getProperty(nextKey))); } try { - myProps.storeToXML(null, "String"); - fail("NullPointerException expected"); - } catch (NullPointerException ee){ - //expected + ByteArrayOutputStream out = new ByteArrayOutputStream(); + myProps.storeToXML(out, null, null); + fail("should throw nullPointerException"); + } catch (NullPointerException ne) { + // expected } } + + /** + * if loading from single line like "hello" without "\n\r" neither "=", it + * should be same as loading from "hello=" + */ + public void testLoadSingleLine() throws Exception{ + Properties props = new Properties(); + InputStream sr = new ByteArrayInputStream("hello".getBytes()); + props.load(sr); + assertEquals(1, props.size()); + } - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "propertyNames", - args = {} - ) - public void test_propertyNames() { - Properties myProps = new Properties(); - myProps.put("Property A", "value 1"); - myProps.put("Property B", "value 2"); - myProps.put("Property C", "value 3"); - - Enumeration e = myProps.propertyNames(); - - int count = 0; - while (e.hasMoreElements()) { - count++; - assertTrue(myProps.containsKey(e.nextElement())); - } - - assertTrue(myProps.size() == count); + public void test_SequentialpropertyNames() { + Properties parent = new Properties(); + parent.setProperty("parent.a.key", "parent.a.value"); + parent.setProperty("parent.b.key", "parent.b.value"); + + Enumeration names = parent.propertyNames(); + assertEquals("parent.a.key", names.nextElement()); + assertEquals("parent.b.key", names.nextElement()); + assertFalse(names.hasMoreElements()); + + Properties current = new Properties(parent); + current.setProperty("current.a.key", "current.a.value"); + current.setProperty("current.b.key", "current.b.value"); + + names = current.propertyNames(); + assertEquals("parent.a.key", names.nextElement()); + assertEquals("current.b.key", names.nextElement()); + assertEquals("parent.b.key", names.nextElement()); + assertEquals("current.a.key", names.nextElement()); + assertFalse(names.hasMoreElements()); + + Properties child = new Properties(current); + child.setProperty("child.a.key", "child.a.value"); + child.setProperty("child.b.key", "child.b.value"); + + names = child.propertyNames(); + assertEquals("parent.a.key", names.nextElement()); + assertEquals("child.b.key", names.nextElement()); + assertEquals("current.b.key", names.nextElement()); + assertEquals("parent.b.key", names.nextElement()); + assertEquals("child.a.key", names.nextElement()); + assertEquals("current.a.key", names.nextElement()); + assertFalse(names.hasMoreElements()); + } + + public void test_SequentialstringPropertyNames() { + Properties parent = new Properties(); + parent.setProperty("parent.a.key", "parent.a.value"); + parent.setProperty("parent.b.key", "parent.b.value"); + + Iterator nameIterator = parent.stringPropertyNames().iterator(); + assertEquals("parent.a.key", nameIterator.next()); + assertEquals("parent.b.key", nameIterator.next()); + assertFalse(nameIterator.hasNext()); + + Properties current = new Properties(parent); + current.setProperty("current.a.key", "current.a.value"); + current.setProperty("current.b.key", "current.b.value"); + + nameIterator = current.stringPropertyNames().iterator(); + assertEquals("parent.a.key", nameIterator.next()); + assertEquals("current.b.key", nameIterator.next()); + assertEquals("parent.b.key", nameIterator.next()); + assertEquals("current.a.key", nameIterator.next()); + assertFalse(nameIterator.hasNext()); + + Properties child = new Properties(current); + child.setProperty("child.a.key", "child.a.value"); + child.setProperty("child.b.key", "child.b.value"); + + nameIterator = child.stringPropertyNames().iterator(); + assertEquals("parent.a.key", nameIterator.next()); + assertEquals("child.b.key", nameIterator.next()); + assertEquals("current.b.key", nameIterator.next()); + assertEquals("parent.b.key", nameIterator.next()); + assertEquals("child.a.key", nameIterator.next()); + assertEquals("current.a.key", nameIterator.next()); + assertFalse(nameIterator.hasNext()); } /** * Sets up the fixture, for example, open a network connection. This method * is called before a test is executed. */ - protected void setUp() throws Exception { - super.setUp(); + protected void setUp() { + tProps = new Properties(); tProps.put("test.prop", "this is a test property"); tProps.put("bogus.prop", "bogus"); @@ -594,14 +1031,17 @@ public class PropertiesTest extends junit.framework.TestCase { * Tears down the fixture, for example, close a network connection. This * method is called after a test is executed. */ - protected void tearDown() throws Exception { - tProps = null; - super.tearDown(); + protected void tearDown() { } + /** + * Tears down the fixture, for example, close a network connection. This + * method is called after a test is executed. + */ protected byte[] writeProperties() throws IOException { + PrintStream ps = null; ByteArrayOutputStream bout = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(bout); + ps = new PrintStream(bout); ps.println("#commented.entry=Bogus"); ps.println("test.pkg=harmony.tests"); ps.println("test.proj=Automated Tests"); @@ -609,10 +1049,29 @@ public class PropertiesTest extends junit.framework.TestCase { return bout.toByteArray(); } - protected byte[] writePropertiesXML(String encoding) throws IOException { + protected byte[] writePropertiesXMLUTF_8() throws IOException { + PrintStream ps = null; + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ps = new PrintStream(bout, true, "UTF-8"); + ps.println(""); + ps + .println(""); + ps.println(""); + ps.println("comment"); + ps.println("value4"); + ps.println("value3"); + ps.println("value2"); + ps.println("value1"); + ps.println(""); + ps.close(); + return bout.toByteArray(); + } + + protected byte[] writePropertiesXMLISO_8859_1() throws IOException { + PrintStream ps = null; ByteArrayOutputStream bout = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(bout, true, encoding); - ps.println(""); + ps = new PrintStream(bout, true, "ISO-8859-1"); + ps.println(""); ps .println(""); ps.println(""); diff --git a/libcore/luni/src/test/java/tests/api/java/util/ResourceBundleTest.java b/libcore/luni/src/test/java/tests/api/java/util/ResourceBundleTest.java index 480c99861..52a2409ba 100644 --- a/libcore/luni/src/test/java/tests/api/java/util/ResourceBundleTest.java +++ b/libcore/luni/src/test/java/tests/api/java/util/ResourceBundleTest.java @@ -188,7 +188,7 @@ public class ResourceBundleTest extends junit.framework.TestCase { } try { - ResourceBundle.getBundle(name, Locale.getDefault(), null); + ResourceBundle.getBundle(name, Locale.getDefault(), (ClassLoader) null); fail("NullPointerException expected"); } catch (NullPointerException ee) { //expected diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java index 3cc447fc5..885d0e5a3 100644 --- a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java +++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java @@ -706,7 +706,7 @@ public class ProviderTest extends TestCase { assertEquals("1.0", myProvider.get("Provider.id version")); try { - myProvider.load(null); + myProvider.load((InputStream) null); fail("NullPointerException expected"); } catch (NullPointerException e) { // expected -- 2.11.0