summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog58
-rw-r--r--java/text/DateFormatSymbols.java304
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c6
3 files changed, 322 insertions, 46 deletions
diff --git a/ChangeLog b/ChangeLog
index 31833447b..b572709d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,60 @@
+2012-07-01 Andrew John Hughes <ahughes@redhat.com>
+
+ PR classpath/44052
+ * java/text/DateFormatSymbols.java:
+ (DFSData): Inner immutable class for storing parsed
+ locale data.
+ (DFSData.DFSData(String[],String[],String,String[],
+ String[],String[],String[],String[],String[],
+ String[][])): Constructor to initialise a new instance
+ with property data.
+ (DFSData.getAMPMs()): Return a clone of the ampms array.
+ (DFSData.getEras()): Likewise for eras.
+ (DFSData.getLocalPatternChars()): Return the local pattern
+ characters.
+ (DFSData.getMonths()): Return a clone of the (long) months
+ array.
+ (DFSData.getShortMonths()): Likewise for the short months array.
+ (DFSData.getWeekdays()): Likewise for (long) weekdays.
+ (DFSData.getShortWeekdays()): Likewise for short weekdays.
+ (DFSData.getDateFormats()): Likewise for date formats.
+ (DFSData.getTimeFormats()): Likewise for time formats.
+ (DFSData.getZoneStrings()): Likewise for zone strings.
+ (dataCache): Cache of parsed locale data.
+ (getZoneStrings(List<ResourceBundle>,Locale)):
+ Make static so it can be called by retrieveData.
+ (formatsForKey(List<ResourceBundle>,String)):
+ Likewise.
+ (getString(List<ResourceBundle>, String)): Likewise.
+ (retrieveData(Locale)): Separate out retrieval of
+ locale data from constructor and store it in the cache.
+ (DateFormatSymbols(Locale)): Modify to call retrieveData
+ and set fields from the returned DFSData instance.
+
+2012-05-30 Andrew John Hughes <ahughes@redhat.com>
+
+ * java/text/DateFormatSymbols.java:
+ (getZoneStrings(List<ResourceBundle>, Locale)):
+ Refactor to use existing list of resource bundles.
+ (formatsForKey(List<ResourceBundle>, String)):
+ Likewise and use new local getString method.
+ (getString(List<ResourceBundle>, String)):
+ Use first available String from most-specific locale
+ rather than the least-specific.
+ (DateFormatSymbols(Locale)): Use bundles for resolving
+ localPatternChars, dateFormats, timeFormats and runtimeZoneStrings
+ as well.
+
+2012-05-04 Andrew John Hughes <ahughes@redhat.com>
+
+ * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c,
+ (font_map): Renamed from ft2_map.
+ (Java_gnu_java_awt_peer_gtk_GdkFontPeer_initStaticState(JNIEnv,
+ jclass)): Remove cast to pango_ft2_font_map_new.
+ (Java_gnu_java_awt_peer_gtk_GdKFontPeer_setFont(JNIEnv,
+ jobject,jstring,jint,jint)): Call pango_font_map_create_context
+ rather than deprecated pango_ft2_font_map_create_context.
+
2012-05-01 Andrew John Hughes <ahughes@redhat.com>
* java/text/DateFormatSymbols.java:
@@ -7,6 +64,7 @@
2012-04-30 Andreas Sewe <sewe@st.informatik.tu-darmstadt.de>
+ PR classpath/53171
* java/text/DateFormatSymbols.java:
(U00A9): Pre-compile pattern for zone separation.
(U00AE): Likewise for fields.
diff --git a/java/text/DateFormatSymbols.java b/java/text/DateFormatSymbols.java
index 6b0d3a13f..9d0ace65a 100644
--- a/java/text/DateFormatSymbols.java
+++ b/java/text/DateFormatSymbols.java
@@ -55,6 +55,10 @@ import java.util.Properties;
import java.util.ResourceBundle;
import java.util.ServiceLoader;
import java.util.TimeZone;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+
import java.util.regex.Pattern;
import java.util.spi.TimeZoneNameProvider;
@@ -72,14 +76,6 @@ import java.util.spi.TimeZoneNameProvider;
*/
public class DateFormatSymbols implements java.io.Serializable, Cloneable
{
- String[] ampms;
- String[] eras;
- private String localPatternChars;
- String[] months;
- String[] shortMonths;
- String[] shortWeekdays;
- String[] weekdays;
-
/**
* The set of properties for obtaining the metazone data.
*/
@@ -106,6 +102,169 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
private static final Pattern FIELD_SEP = Pattern.compile("\u00ae");
/**
+ * Class for storing DateFormatSymbols data parsed from the property files.
+ */
+ private static class DFSData
+ {
+ private String[] ampms;
+ private String[] eras;
+ private String localPatternChars;
+ private String[] months;
+ private String[] shortMonths;
+ private String[] weekdays;
+ private String[] shortWeekdays;
+ private String[] dateFormats;
+ private String[] timeFormats;
+ private String[][] runtimeZoneStrings;
+
+ /**
+ * Construct a new instance with the parsed data.
+ *
+ * @param ampms strings for "am" and "pm".
+ * @param eras strings for calendar eras.
+ * @param localPatternChars localised pattern characters.
+ * @param months strings for the months of the year.
+ * @param shortMonths short strings for the months of the year.
+ * @param weekdays strings for the days of the week.
+ * @param shortWeekdays short strings for the days of the week.
+ * @param dateFormats localised date formats.
+ * @param timeFormats localised time formats.
+ * @param runtimeZoneStrings localised time zone names.
+ */
+ public DFSData(String[] ampms, String[] eras, String localPatternChars,
+ String[] months, String[] shortMonths, String[] weekdays,
+ String[] shortWeekdays, String[] dateFormats,
+ String[] timeFormats, String[][] runtimeZoneStrings)
+ {
+ this.ampms = ampms;
+ this.eras = eras;
+ this.localPatternChars = localPatternChars;
+ this.months = months;
+ this.shortMonths = shortMonths;
+ this.weekdays = weekdays;
+ this.shortWeekdays = shortWeekdays;
+ this.dateFormats = dateFormats;
+ this.timeFormats = timeFormats;
+ this.runtimeZoneStrings = runtimeZoneStrings;
+ }
+
+ /**
+ * Accessor for the AM/PM data.
+ *
+ * @return the AM/PM strings.
+ */
+ public String[] getAMPMs()
+ {
+ return ampms.clone();
+ }
+
+ /**
+ * Accessor for the era data.
+ *
+ * @return the era strings.
+ */
+ public String[] getEras()
+ {
+ return eras.clone();
+ }
+
+ /**
+ * Accessor for the local pattern characters.
+ *
+ * @return the local pattern characters.
+ */
+ public String getLocalPatternChars()
+ {
+ return localPatternChars;
+ }
+
+ /**
+ * Accessor for the months of the year (long form).
+ *
+ * @return the months of the year (long form).
+ */
+ public String[] getMonths()
+ {
+ return months.clone();
+ }
+
+ /**
+ * Accessor for the months of the year (short form).
+ *
+ * @return the months of the year (short form).
+ */
+ public String[] getShortMonths()
+ {
+ return shortMonths.clone();
+ }
+
+ /**
+ * Accessor for the days of the week (long form).
+ *
+ * @return the days of the week (long form).
+ */
+ public String[] getWeekdays()
+ {
+ return weekdays.clone();
+ }
+
+ /**
+ * Accessor for the days of the week (short form).
+ *
+ * @return the days of the week (short form).
+ */
+ public String[] getShortWeekdays()
+ {
+ return shortWeekdays.clone();
+ }
+
+ /**
+ * Accessor for the date formats.
+ *
+ * @return the date formats.
+ */
+ public String[] getDateFormats()
+ {
+ return dateFormats.clone();
+ }
+
+ /**
+ * Accessor for the time formats.
+ *
+ * @return the time formats.
+ */
+ public String[] getTimeFormats()
+ {
+ return timeFormats.clone();
+ }
+
+ /**
+ * Accessor for the zone strings.
+ *
+ * @return the zone strings.
+ */
+ public String[][] getZoneStrings()
+ {
+ // Perform a deep clone so subarrays aren't modifiable
+ String[][] clone = runtimeZoneStrings.clone();
+ for (int a = 0; a < clone.length; ++a)
+ clone[a] = runtimeZoneStrings[a].clone();
+ return clone;
+ }
+
+ }
+
+ private static final ConcurrentMap<Locale, DFSData> dataCache = new ConcurrentHashMap<Locale, DFSData>();
+
+ String[] ampms;
+ String[] eras;
+ private String localPatternChars;
+ String[] months;
+ String[] shortMonths;
+ String[] shortWeekdays;
+ String[] weekdays;
+
+ /**
* The timezone strings supplied by the runtime.
*/
private String[][] runtimeZoneStrings;
@@ -185,17 +344,16 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
return data;
}
- private String[][] getZoneStrings(ResourceBundle res, Locale locale)
+ private static String[][] getZoneStrings(List<ResourceBundle> bundles, Locale locale)
{
List<String[]> allZones = new ArrayList<String[]>();
try
{
Map<String,String[]> systemZones = new HashMap<String,String[]>();
- while (true)
+ for (ResourceBundle bundle : bundles)
{
- int index = 0;
String country = locale.getCountry();
- String data = res.getString("zoneStrings");
+ String data = bundle.getString("zoneStrings");
String[] zones = ZONE_SEP.split(data);
for (int a = 0; a < zones.length; ++a)
{
@@ -222,12 +380,6 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
}
systemZones.put(strings[0], strings);
}
- if (res.getLocale() == Locale.ROOT)
- break;
- else
- res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
- LocaleHelper.getFallbackLocale(res.getLocale()),
- ClassLoader.getSystemClassLoader());
}
/* Final sanity check for missing values */
for (String[] zstrings : systemZones.values())
@@ -293,17 +445,95 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
return allZones.toArray(new String[allZones.size()][]);
}
- private String[] formatsForKey(ResourceBundle res, String key)
+ /**
+ * Retrieve the date or time formats for a specific key e.g.
+ * asking for "DateFormat" will return an array containing the
+ * full, long, medium and short date formats localised for
+ * the locales in the specified bundle.
+ *
+ * @param bundles the stack of bundles to check, most-specific first.
+ * @param key the type of format to retrieve.
+ * @param an array of localised strings for each format prefix.
+ */
+ private static String[] formatsForKey(List<ResourceBundle> bundles, String key)
{
String[] values = new String[formatPrefixes.length];
for (int i = 0; i < formatPrefixes.length; i++)
- values[i] = res.getString(formatPrefixes[i] + key);
+ values[i] = getString(bundles, formatPrefixes[i] + key);
return values;
}
/**
+ * Simple wrapper around extracting a {@code String} from a
+ * {@code ResourceBundle}. Keep searching less-specific locales
+ * until a non-null non-empty value is found.
+ *
+ * @param bundles the stack of bundles to check, most-specific first.
+ * @param key the key of the value to retrieve.
+ * @return the first non-null non-empty String found or the last
+ * retrieved if one isn't found.
+ */
+ private static String getString(List<ResourceBundle> bundles, String key)
+ {
+ String val = null;
+ for (ResourceBundle bundle : bundles)
+ {
+ val = bundle.getString(key);
+ if (val != null && !val.isEmpty())
+ return val;
+ }
+ return val;
+ }
+
+ /**
+ * Retrieves the locale data from the property files and constructs a
+ * {@code DFSData} instance for it.
+ *
+ * @param the locale for which data should be retrieved.
+ * @return the parsed data.
+ * @throws MissingResourceException if the resources for the specified
+ * locale could not be found or loaded.
+ */
+ private static DFSData retrieveData(Locale locale)
+ throws MissingResourceException
+ {
+ DFSData data = dataCache.get(locale);
+ if (data == null)
+ {
+ ClassLoader ldr = ClassLoader.getSystemClassLoader();
+ List<ResourceBundle> bundles = new ArrayList<ResourceBundle>();
+ ResourceBundle res
+ = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, ldr);
+ bundles.add(res);
+ Locale resLocale = res.getLocale();
+ while (resLocale != Locale.ROOT)
+ {
+ res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ LocaleHelper.getFallbackLocale(resLocale), ldr);
+ bundles.add(res);
+ resLocale = res.getLocale();
+ }
+ String[] lMonths = getStringArray(bundles, "months", 13);
+ String[] lWeekdays = getStringArray(bundles, "weekdays", 8);
+ data = new DFSData(getStringArray(bundles, "ampms", 2),
+ getStringArray(bundles, "eras", 2),
+ getString(bundles, "localPatternChars"),
+ lMonths, getStringArray(bundles, "shortMonths", 13, lMonths),
+ lWeekdays, getStringArray(bundles, "shortWeekdays", 8, lWeekdays),
+ formatsForKey(bundles, "DateFormat"),
+ formatsForKey(bundles, "TimeFormat"),
+ getZoneStrings(bundles, locale));
+ DFSData cachedData = dataCache.putIfAbsent(locale, data);
+ // Use the earlier version if another thread beat us to it.
+ if (cachedData != null)
+ data = cachedData;
+ }
+ return data;
+ }
+
+ /**
* This method initializes a new instance of <code>DateFormatSymbols</code>
* by loading the date format information for the specified locale.
* This constructor only obtains instances using the runtime's resources;
@@ -319,29 +549,17 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
public DateFormatSymbols (Locale locale)
throws MissingResourceException
{
- ClassLoader ldr = ClassLoader.getSystemClassLoader();
- List<ResourceBundle> bundles = new ArrayList<ResourceBundle>();
- ResourceBundle res
- = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, ldr);
- bundles.add(res);
- Locale resLocale = res.getLocale();
- while (resLocale != Locale.ROOT)
- {
- res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
- LocaleHelper.getFallbackLocale(resLocale), ldr);
- bundles.add(res);
- resLocale = res.getLocale();
- }
- ampms = getStringArray(bundles, "ampms", 2);
- eras = getStringArray(bundles, "eras", 2);
- localPatternChars = res.getString("localPatternChars");
- months = getStringArray(bundles, "months", 13);
- shortMonths = getStringArray(bundles, "shortMonths", 13, months);
- weekdays = getStringArray(bundles, "weekdays", 8);
- shortWeekdays = getStringArray(bundles, "shortWeekdays", 8, weekdays);
- dateFormats = formatsForKey(res, "DateFormat");
- timeFormats = formatsForKey(res, "TimeFormat");
- runtimeZoneStrings = getZoneStrings(res, locale);
+ DFSData data = retrieveData(locale);
+ ampms = data.getAMPMs();
+ eras = data.getEras();
+ localPatternChars = data.getLocalPatternChars();
+ months = data.getMonths();
+ shortMonths = data.getShortMonths();
+ weekdays = data.getWeekdays();
+ shortWeekdays = data.getShortWeekdays();
+ dateFormats = data.getDateFormats();
+ timeFormats = data.getTimeFormats();
+ runtimeZoneStrings = data.getZoneStrings();
}
/**
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c
index a5e59f7e4..771b23e37 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c
@@ -59,14 +59,14 @@ enum java_awt_font_baseline {
java_awt_font_HANGING_BASELINE = 2
};
-static PangoFT2FontMap *ft2_map = NULL;
+static PangoFontMap *font_map = NULL;
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GdkFontPeer_initStaticState
(JNIEnv *env, jclass clazz __attribute__((unused)))
{
gtkpeer_init_font_IDs(env);
- ft2_map = PANGO_FT2_FONT_MAP(pango_ft2_font_map_new());
+ font_map = pango_ft2_font_map_new();
}
JNIEXPORT void JNICALL
@@ -287,7 +287,7 @@ Java_gnu_java_awt_peer_gtk_GdkFontPeer_setFont
pango_font_description_set_size (pfont->desc, size * PANGO_SCALE);
/* Create new context */
- pfont->ctx = pango_ft2_font_map_create_context (ft2_map);
+ pfont->ctx = pango_font_map_create_context (font_map);
g_assert (pfont->ctx != NULL);
pango_context_set_font_description (pfont->ctx, pfont->desc);