Author: desruisseaux
Date: Tue Feb 5 15:44:29 2013
New Revision: 1442629
URL: http://svn.apache.org/viewvc?rev=1442629&view=rev
Log:
Let ResourceBundle creates itself the chain of parents.
This allow better choices of formats for numbers and dates.
Added:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
(with props)
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
Tue Feb 5 15:44:29 2013
@@ -16,6 +16,7 @@
*/
package org.apache.sis.util.resources;
+import java.net.URL;
import java.util.Locale;
import java.util.MissingResourceException;
import org.opengis.util.InternationalString;
@@ -397,10 +398,11 @@ public final class Errors extends Indexe
/**
* Constructs a new resource bundle loading data from the given UTF file.
*
- * @param filename The file or the JAR entry containing resources.
+ * @param resources The path of the binary file containing resources, or
{@code null} if
+ * there is no resources. The resources may be a file or an entry
in a JAR file.
*/
- Errors(final String filename) {
- super(filename);
+ Errors(final URL resources) {
+ super(resources);
}
/**
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
Tue Feb 5 15:44:29 2013
@@ -16,11 +16,10 @@
*/
package org.apache.sis.util.resources;
+import java.net.URL;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Locale;
@@ -67,33 +66,23 @@ public class IndexedResourceBundle exten
private static final int MAX_STRING_LENGTH = 200;
/**
- * The resource name of the binary file containing resources. It may be a
file name or an
- * entry in a JAR file. The path must be relative to the package
containing the subclass
- * of {@code IndexedResourceBundle}.
+ * The path of the binary file containing resources, or {@code null} if
there is no resources
+ * of if the resources have already been loaded. The resources may be a
file or an entry in a
+ * JAR file.
*/
- private final String filename;
+ private URL resources;
/**
* The array of resources. Keys are an array index. For example, the value
for key "14" is
* {@code values[14]}. This array will be loaded only when first needed.
We should not load
* it at construction time, because some {@code ResourceBundle} objects
will never ask for
- * values. This is particularly the case for ancestor classes of {@code
Resources_fr_CA},
+ * values. This is particularly the case for parent resources of {@code
Resources_fr_CA},
* {@code Resources_en}, {@code Resources_de}, etc., which will only be
used if a key has
- * not been found in the subclass.
+ * not been found in the child resources.
*
* @see #ensureLoaded(String)
*/
- private String[] values;
-
- /**
- * The locale for formatting objects like number, date, etc. There are two
possible Locales
- * we could use: default locale or resource bundle locale. If the default
locale uses the same
- * language as this ResourceBundle's locale, then we will use the default
locale. This allows
- * dates and numbers to be formatted according to user conventions (e.g.
French Canada) even
- * if the ResourceBundle locale is different (e.g. standard French).
However, if languages
- * don't match, then we will use ResourceBundle locale for better
coherence.
- */
- private transient Locale formatLocale;
+ private volatile String[] values;
/**
* The object to use for formatting messages. This object
@@ -111,11 +100,11 @@ public class IndexedResourceBundle exten
/**
* Constructs a new resource bundle loading data from the given UTF file.
*
- * @param filename The file or the JAR entry containing resources. The
path must be relative
- * to the package of the {@code IndexedResourceBundle} subclass
being constructed.
+ * @param resources The path of the binary file containing resources, or
{@code null} if
+ * there is no resources. The resources may be a file or an entry
in a JAR file.
*/
- protected IndexedResourceBundle(final String filename) {
- this.filename = filename;
+ protected IndexedResourceBundle(final URL resources) {
+ this.resources = resources;
}
/**
@@ -141,24 +130,6 @@ public class IndexedResourceBundle exten
}
/**
- * Returns the locale to use for formatters. It is often the same than
{@link #getLocale()},
- * except if the later has the same language than the default locale, in
which case this
- * method returns the default locale. For example if this {@code
IndexResourceBundle} is
- * for the French locale but the user is French Canadian, we will format
the dates using
- * Canada French conventions rather than France conventions.
- */
- private Locale getFormatLocale() {
- if (formatLocale == null) {
- formatLocale = Locale.getDefault();
- final Locale rl = getLocale(); // Sometime null with IBM's JDK.
- if (rl != null &&
!formatLocale.getLanguage().equalsIgnoreCase(rl.getLanguage())) {
- formatLocale = rl;
- }
- }
- return formatLocale;
- }
-
- /**
* Returns a handler for the constants declared in the inner {@code Keys}
class.
* Subclasses defined in the {@code org.apache.sis.util.resources} package
* override this method for efficiency. However the default implementation
@@ -269,75 +240,73 @@ public class IndexedResourceBundle exten
* @throws MissingResourceException if this method failed to load
resources.
*/
private String[] ensureLoaded(final String key) throws
MissingResourceException {
- final String methodName = (key != null) ? "getObject" : "getKeys";
- LogRecord record = null;
- try {
- String[] values;
- synchronized (this) {
- values = this.values;
- if (values != null) {
- return values;
- }
+ String[] values = this.values;
+ if (values == null) synchronized (this) {
+ values = this.values;
+ if (values == null) {
/*
- * Prepares a log record. We will wait for successful loading
before
- * posting this record. If loading fails, the record will be
changed
- * into an error record. Note that the message must be logged
outside
- * the synchronized block, otherwise there is dead locks!
+ * If there is no explicit resources for this instance,
inherit the resources
+ * from the parent. Note that this IndexedResourceBundle
instance may still
+ * differ from its parent in the way date and numbers are
formatted.
*/
- record = new LogRecord(Level.FINER, "Loaded resources for {0}
from bundle \"{1}\".");
- /*
- * Loads resources from the UTF file.
- */
- InputStream in;
- String name = filename;
- while ((in = getClass().getResourceAsStream(name)) == null) {
// NOSONAR
- final int ext = name.lastIndexOf('.');
- final int lang = name.lastIndexOf('_', ext-1);
- if (lang <= 0) {
- throw new FileNotFoundException(filename);
- }
- final int length = name.length();
- name = new StringBuilder(lang + (length-ext))
- .append(name, 0, lang).append(name, ext,
length).toString();
- }
- try (DataInputStream input = new DataInputStream(new
BufferedInputStream(in))) {
- this.values = values = new String[input.readInt()];
- for (int i=0; i<values.length; i++) {
- values[i] = input.readUTF();
- if (values[i].isEmpty()) {
- values[i] = null;
+ if (resources == null) {
+ // If we get a NullPointerException or ClassCastException
here,
+ // it would be a bug in the way we create the chain of
parents.
+ values = ((IndexedResourceBundle)
parent).ensureLoaded(key);
+ } else {
+ /*
+ * Prepares a log record. We will wait for successful
loading before
+ * posting this record. If loading fails, the record will
be changed
+ * into an error record. Note that the message must be
logged outside
+ * the synchronized block, otherwise there is dead locks!
+ */
+ final Locale locale = getLocale(); // Sometime null
with IBM's JDK.
+ final String baseName = getClass().getCanonicalName();
+ final String methodName = (key != null) ? "getObject" :
"getKeys";
+ final LogRecord record = new LogRecord(Level.FINER,
"Loaded resources for {0} from bundle \"{1}\".");
+ /*
+ * Loads resources from the UTF file.
+ */
+ try (DataInputStream input = new DataInputStream(new
BufferedInputStream(resources.openStream()))) {
+ values = new String[input.readInt()];
+ for (int i=0; i<values.length; i++) {
+ values[i] = input.readUTF();
+ if (values[i].isEmpty()) {
+ values[i] = null;
+ }
}
+ } catch (IOException exception) {
+ record.setLevel (Level.WARNING);
+ record.setMessage(exception.getMessage()); // For
administrator, use system locale.
+ record.setThrown (exception);
+ Logging.log(IndexedResourceBundle.class, methodName,
record);
+ final MissingResourceException error = new
MissingResourceException(
+ Exceptions.getLocalizedMessage(exception,
locale), // For users, use requested locale.
+ baseName, key);
+ error.initCause(exception);
+ throw error;
}
+ /*
+ * Now, logs the message. This message is provided only in
English.
+ * Note that Locale.getDisplayName() may return different
string on
+ * different Java implementation, but it doesn't matter
here since
+ * we use the result only for logging purpose.
+ */
+ String language = null;
+ if (locale != null) {
+ language = locale.getDisplayName(Locale.US);
+ }
+ if (language == null || language.isEmpty()) {
+ language = "<root>";
+ }
+ record.setParameters(new String[] {language, baseName});
+ Logging.log(IndexedResourceBundle.class, methodName,
record);
+ resources = null; // Not needed anymore, let GC do its job.
}
- /*
- * Now, logs the message. This message is provided only in
English.
- * Note that Locale.getDisplayName() may return different
string on
- * different Java implementation, but it doesn't matter here
since
- * we use the result only for logging purpose.
- */
- String language = null;
- final Locale rl = getLocale(); // Sometime null with IBM's JDK.
- if (rl != null) {
- language = rl.getDisplayName(Locale.US);
- }
- if (language == null || language.isEmpty()) {
- language = "<default>";
- }
- record.setParameters(new String[] {language,
getClass().getCanonicalName()});
+ this.values = values;
}
- Logging.log(IndexedResourceBundle.class, methodName, record);
- return values;
- } catch (IOException exception) {
- record.setLevel (Level.WARNING);
- record.setMessage(exception.getMessage()); // For administrator,
use system locale.
- record.setThrown (exception);
- Logging.log(IndexedResourceBundle.class, methodName, record);
- final MissingResourceException error = new
MissingResourceException(
- Exceptions.getLocalizedMessage(exception, getLocale()), //
For users, use requested locale.
- getClass().getCanonicalName(), key);
- error.initCause(exception);
- throw error;
}
+ return values;
}
/**
@@ -400,11 +369,11 @@ public class IndexedResourceBundle exten
if (element instanceof CharSequence) {
CharSequence text = (CharSequence) element;
if (text instanceof InternationalString) {
- text = ((InternationalString)
element).toString(getFormatLocale());
+ text = ((InternationalString)
element).toString(getLocale());
}
replacement = CharSequences.shortSentence(text,
MAX_STRING_LENGTH);
} else if (element instanceof Throwable) {
- String message = Exceptions.getLocalizedMessage((Throwable)
element, getFormatLocale());
+ String message = Exceptions.getLocalizedMessage((Throwable)
element, getLocale());
if (message == null) {
message = Classes.getShortClassName(element);
}
@@ -492,7 +461,7 @@ public class IndexedResourceBundle exten
/*
* Constructs a new MessageFormat for formatting the arguments.
*/
- format = new MessageFormat(pattern, getFormatLocale());
+ format = new MessageFormat(pattern, getLocale());
lastKey = key;
} else if (key != lastKey) {
/*
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java
Tue Feb 5 15:44:29 2013
@@ -16,6 +16,7 @@
*/
package org.apache.sis.util.resources;
+import java.net.URL;
import java.util.List;
import java.util.Locale;
import java.util.Collections;
@@ -105,25 +106,16 @@ final class Loader extends ResourceBundl
* bundle only if the file is found.
*/
final String classname = classe.getSimpleName();
- String filename = toResourceName(toBundleName(classname, locale),
EXTENSION);
- if (classe.getResource(filename) == null) {
- if (!Locale.ENGLISH.equals(locale)) {
- return null;
- }
- // We have no explicit resources for English. We use the default
one for that.
- filename = toResourceName(classname, EXTENSION);
- if (classe.getResource(filename) == null) {
- return null;
- }
- }
+ final URL resources =
classe.getResource(toResourceName(toBundleName(classname, locale), EXTENSION));
/*
- * If the file exists, instantiate now the resource bundle. Note that
the constructor
- * will not loads the data immediately, which is why we don't pass it
the above URL.
+ * Instantiate now the resource bundle. The resources URL may be null,
in which case the
+ * bundle will inherit the strings from the parent bundle. In every
cases, the strings
+ * will be loaded only when first needed.
*
* Note: Do not call Constructor.setAccessible(true) - this is not
allowed in Applet.
*/
try {
- return (ResourceBundle)
classe.getDeclaredConstructor(String.class).newInstance(filename);
+ return (ResourceBundle)
classe.getDeclaredConstructor(URL.class).newInstance(resources);
} catch (NoSuchMethodException | InvocationTargetException e) {
InstantiationException exception = new
InstantiationException(Exceptions.getLocalizedMessage(e, locale));
exception.initCause(e);
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
Tue Feb 5 15:44:29 2013
@@ -16,6 +16,7 @@
*/
package org.apache.sis.util.resources;
+import java.net.URL;
import java.util.Locale;
import java.util.MissingResourceException;
import org.opengis.util.InternationalString;
@@ -67,10 +68,11 @@ public final class Messages extends Inde
/**
* Constructs a new resource bundle loading data from the given UTF file.
*
- * @param filename The file or the JAR entry containing resources.
+ * @param resources The path of the binary file containing resources, or
{@code null} if
+ * there is no resources. The resources may be a file or an entry
in a JAR file.
*/
- Messages(final String filename) {
- super(filename);
+ Messages(final URL resources) {
+ super(resources);
}
/**
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
Tue Feb 5 15:44:29 2013
@@ -16,6 +16,7 @@
*/
package org.apache.sis.util.resources;
+import java.net.URL;
import java.util.Locale;
import java.util.MissingResourceException;
import org.opengis.util.InternationalString;
@@ -247,10 +248,11 @@ public final class Vocabulary extends In
/**
* Constructs a new resource bundle loading data from the given UTF file.
*
- * @param filename The file or the JAR entry containing resources.
+ * @param resources The path of the binary file containing resources, or
{@code null} if
+ * there is no resources. The resources may be a file or an entry
in a JAR file.
*/
- Vocabulary(final String filename) {
- super(filename);
+ Vocabulary(final URL resources) {
+ super(resources);
}
/**
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
(original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
Tue Feb 5 15:44:29 2013
@@ -42,6 +42,7 @@ import org.junit.runners.Suite;
org.apache.sis.util.ClassesTest.class,
org.apache.sis.util.VersionTest.class,
org.apache.sis.util.LocalesTest.class,
+ org.apache.sis.util.resources.LoaderTest.class,
org.apache.sis.util.resources.IndexedResourceBundleTest.class,
org.apache.sis.util.logging.PerformanceLevelTest.class,
org.apache.sis.math.MathFunctionsTest.class,
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java?rev=1442629&r1=1442628&r2=1442629&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
(original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
Tue Feb 5 15:44:29 2013
@@ -40,7 +40,7 @@ import static org.apache.sis.test.Assert
* @since 0.3 (derived from geotk-2.2)
* @version 0.3
*/
-@DependsOn(org.apache.sis.util.ArraysExtTest.class)
+@DependsOn(LoaderTest.class)
public final strictfp class IndexedResourceBundleTest extends TestCase {
/**
* The resource bundle in process of being tested. Shall be reset to
{@code null} after every
@@ -56,14 +56,18 @@ public final strictfp class IndexedResou
public void testGetResources() {
final Errors english = Errors.getResources(Locale.ENGLISH);
final Errors french = Errors.getResources(Locale.FRENCH);
+ final Errors canada = Errors.getResources(Locale.CANADA);
+ final Errors quebec = Errors.getResources(Locale.CANADA_FRENCH);
+ assertNotSame(english, Errors.getResources(Locale.US));
+ assertNotSame(english, Errors.getResources(Locale.UK));
assertNotSame(english, french);
+ assertNotSame(english, canada);
+ assertNotSame(french, quebec);
assertSame(english, Errors.getResources(Locale.ENGLISH));
- assertSame(english, Errors.getResources(Locale.US));
- assertSame(english, Errors.getResources(Locale.UK));
- assertSame(english, Errors.getResources(Locale.CANADA));
+ assertSame(canada, Errors.getResources(Locale.CANADA));
assertSame(french, Errors.getResources(Locale.FRENCH));
- assertSame(french, Errors.getResources(Locale.CANADA_FRENCH));
+ assertSame(quebec, Errors.getResources(Locale.CANADA_FRENCH));
}
/**
Added:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java?rev=1442629&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
(added)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
Tue Feb 5 15:44:29 2013
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.resources;
+
+import java.util.Locale;
+import java.util.List;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Tests the {@link Loader} class.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ */
+public final strictfp class LoaderTest extends TestCase {
+ /**
+ * Tests the {@link Loader#getCandidateLocales(String, Locale)} method
+ * for {@link Locale#US}.
+ */
+ @Test
+ public void testCandidateLocalesForUS() {
+ final List<Locale> locales = Loader.INSTANCE.getCandidateLocales(
+ "org.apache.sis.util.resources.Vocabulary", Locale.US);
+ assertEquals("locales.size()", 3, locales.size());
+ assertEquals("locales[0]", Locale.US, locales.get(0));
+ assertEquals("locales[1]", Locale.ENGLISH, locales.get(1));
+ assertEquals("locales[2]", Locale.ROOT, locales.get(2));
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain