8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import sun.util.locale.provider.CalendarDataUtility;
public class BuddhistCalendar extends GregorianCalendar {
//////////////////
// Class Variables
//////////////////
private static final long serialVersionUID = -8527488697350388578L;
private static final int BUDDHIST_YEAR_OFFSET = 543;
///////////////
// Constructors
///////////////
/**
* Constructs a default BuddhistCalendar using the current time
* in the default time zone with the default locale.
*/
public BuddhistCalendar() {
super();
}
/**
* Constructs a BuddhistCalendar based on the current time
* in the given time zone with the default locale.
* @param zone the given time zone.
*/
public BuddhistCalendar(TimeZone zone) {
super(zone);
}
/**
* Constructs a BuddhistCalendar based on the current time
* in the default time zone with the given locale.
* @param aLocale the given locale.
*/
public BuddhistCalendar(Locale aLocale) {
super(aLocale);
}
/**
* Constructs a BuddhistCalendar based on the current time
* in the given time zone with the given locale.
* @param zone the given time zone.
* @param aLocale the given locale.
*/
public BuddhistCalendar(TimeZone zone, Locale aLocale) {
super(zone, aLocale);
}
/////////////////
// Public methods
/////////////////
/**
* Returns {@code "buddhist"} as the calendar type of this Calendar.
*/
@Override
public String getCalendarType() {
return "buddhist";
}
/**
* Compares this BuddhistCalendar to an object reference.
* @param obj the object reference with which to compare
* @return true if this object is equal to <code>obj</code>; false otherwise
*/
@Override
public boolean equals(Object obj) {
return obj instanceof BuddhistCalendar
&& super.equals(obj);
}
/**
* Override hashCode.
* Generates the hash code for the BuddhistCalendar object
*/
@Override
public int hashCode() {
return super.hashCode() ^ BUDDHIST_YEAR_OFFSET;
}
/**
* Gets the value for a given time field.
* @param field the given time field.
* @return the value for the given time field.
*/
@Override
public int get(int field)
{
if (field == YEAR) {
return super.get(field) + yearOffset;
}
return super.get(field);
}
/**
* Sets the time field with the given value.
* @param field the given time field.
* @param value the value to be set for the given time field.
*/
@Override
public void set(int field, int value)
{
if (field == YEAR) {
super.set(field, value - yearOffset);
} else {
super.set(field, value);
}
}
/**
* Adds the specified (signed) amount of time to the given time field.
* @param field the time field.
* @param amount the amount of date or time to be added to the field.
*/
@Override
public void add(int field, int amount)
{
int savedYearOffset = yearOffset;
// To let the superclass calculate date-time values correctly,
// temporarily make this GregorianCalendar.
yearOffset = 0;
try {
super.add(field, amount);
} finally {
yearOffset = savedYearOffset;
}
}
/**
* Add to field a signed amount without changing larger fields.
* A negative roll amount means to subtract from field without changing
* larger fields.
* @param field the time field.
* @param amount the signed amount to add to <code>field</code>.
*/
@Override
public void roll(int field, int amount)
{
int savedYearOffset = yearOffset;
// To let the superclass calculate date-time values correctly,
// temporarily make this GregorianCalendar.
yearOffset = 0;
try {
super.roll(field, amount);
} finally {
yearOffset = savedYearOffset;
}
}
@Override
public String getDisplayName(int field, int style, Locale locale) {
if (field != ERA) {
return super.getDisplayName(field, style, locale);
}
return CalendarDataUtility.retrieveFieldValueName("buddhist", field, get(field), style, locale);
}
@Override
public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
if (field != ERA) {
return super.getDisplayNames(field, style, locale);
}
return CalendarDataUtility.retrieveFieldValueNames("buddhist", field, style, locale);
}
/**
* Returns the maximum value that this field could have, given the
* current date. For example, with the date "Feb 3, 2540" and the
* <code>DAY_OF_MONTH</code> field, the actual maximum is 28; for
* "Feb 3, 2539" it is 29.
*
* @param field the field to determine the maximum of
* @return the maximum of the given field for the current date of this Calendar
*/
@Override
public int getActualMaximum(int field) {
int savedYearOffset = yearOffset;
// To let the superclass calculate date-time values correctly,
// temporarily make this GregorianCalendar.
yearOffset = 0;
try {
return super.getActualMaximum(field);
} finally {
yearOffset = savedYearOffset;
}
}
@Override
@SuppressWarnings("empty-statement")
public String toString() {
// The super class produces a String with the Gregorian year
// value (or '?')
String s = super.toString();
// If the YEAR field is UNSET, then return the Gregorian string.
if (!isSet(YEAR)) {
return s;
}
final String yearField = "YEAR=";
int p = s.indexOf(yearField);
// If the string doesn't include the year value for some
// reason, then return the Gregorian string.
if (p == -1) {
return s;
}
p += yearField.length();
StringBuilder sb = new StringBuilder(s.length() + 10);
sb.append(s, 0, p);
// Skip the year number
while (Character.isDigit(s.charAt(p++)))
;
int year = internalGet(YEAR) + BUDDHIST_YEAR_OFFSET;
sb.append(year).append(s, p - 1, s.length());
return sb.toString();
}
private transient int yearOffset = BUDDHIST_YEAR_OFFSET;
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
yearOffset = BUDDHIST_YEAR_OFFSET;
}
}

View file

@ -0,0 +1,287 @@
/*
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.NoSuchElementException;
/**
* A precomputed hash map.
*
* <p> Subclasses of this class are of the following form:
*
* <blockquote><pre>
* class FooMap
* extends sun.util.PreHashedMap&lt;String&gt;
* {
*
* private FooMap() {
* super(ROWS, SIZE, SHIFT, MASK);
* }
*
* protected void init(Object[] ht) {
* ht[0] = new Object[] { "key-1", value_1 };
* ht[1] = new Object[] { "key-2", value_2,
* new Object { "key-3", value_3 } };
* ...
* }
*
* }</pre></blockquote>
*
* <p> The {@code init} method is invoked by the {@code PreHashedMap}
* constructor with an object array long enough for the map's rows. The method
* must construct the hash chain for each row and store it in the appropriate
* element of the array.
*
* <p> Each entry in the map is represented by a unique hash-chain node. The
* final node of a hash chain is a two-element object array whose first element
* is the entry's key and whose second element is the entry's value. A
* non-final node of a hash chain is a three-element object array whose first
* two elements are the entry's key and value and whose third element is the
* next node in the chain.
*
* <p> Instances of this class are mutable and are not safe for concurrent
* access. They may be made immutable and thread-safe via the appropriate
* methods in the {@link java.util.Collections} utility class.
*
* <p> In the JDK build, subclasses of this class are typically created via the
* {@code Hasher} program in the {@code make/tools/Hasher} directory.
*
* @author Mark Reinhold
* @since 1.5
*
* @see java.util.AbstractMap
*/
public abstract class PreHashedMap<V>
extends AbstractMap<String,V>
{
private final int rows;
private final int size;
private final int shift;
private final int mask;
private final Object[] ht;
/**
* Creates a new map.
*
* <p> This constructor invokes the {@link #init init} method, passing it a
* newly-constructed row array that is {@code rows} elements long.
*
* @param rows
* The number of rows in the map
* @param size
* The number of entries in the map
* @param shift
* The value by which hash codes are right-shifted
* @param mask
* The value with which hash codes are masked after being shifted
*/
protected PreHashedMap(int rows, int size, int shift, int mask) {
this.rows = rows;
this.size = size;
this.shift = shift;
this.mask = mask;
this.ht = new Object[rows];
init(ht);
}
/**
* Initializes this map.
*
* <p> This method must construct the map's hash chains and store them into
* the appropriate elements of the given hash-table row array.
*
* @param ht The row array to be initialized
*/
protected abstract void init(Object[] ht);
@SuppressWarnings("unchecked")
private V toV(Object x) {
return (V)x;
}
public V get(Object k) {
int h = (k.hashCode() >> shift) & mask;
Object[] a = (Object[])ht[h];
if (a == null) return null;
for (;;) {
if (a[0].equals(k))
return toV(a[1]);
if (a.length < 3)
return null;
a = (Object[])a[2];
}
}
/**
* @throws UnsupportedOperationException
* If the given key is not part of this map's initial key set
*/
public V put(String k, V v) {
int h = (k.hashCode() >> shift) & mask;
Object[] a = (Object[])ht[h];
if (a == null)
throw new UnsupportedOperationException(k);
for (;;) {
if (a[0].equals(k)) {
V ov = toV(a[1]);
a[1] = v;
return ov;
}
if (a.length < 3)
throw new UnsupportedOperationException(k);
a = (Object[])a[2];
}
}
public Set<String> keySet() {
return new AbstractSet<> () {
public int size() {
return size;
}
public Iterator<String> iterator() {
return new Iterator<>() {
private int i = -1;
Object[] a = null;
String cur = null;
private boolean findNext() {
if (a != null) {
if (a.length == 3) {
a = (Object[])a[2];
cur = (String)a[0];
return true;
}
i++;
a = null;
}
cur = null;
if (i >= rows)
return false;
if (i < 0 || ht[i] == null) {
do {
if (++i >= rows)
return false;
} while (ht[i] == null);
}
a = (Object[])ht[i];
cur = (String)a[0];
return true;
}
public boolean hasNext() {
if (cur != null)
return true;
return findNext();
}
public String next() {
if (cur == null) {
if (!findNext())
throw new NoSuchElementException();
}
String s = cur;
cur = null;
return s;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
public Set<Map.Entry<String,V>> entrySet() {
return new AbstractSet<Map.Entry<String,V>> () {
public int size() {
return size;
}
public Iterator<Map.Entry<String,V>> iterator() {
return new Iterator<Map.Entry<String,V>>() {
final Iterator<String> i = keySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public Map.Entry<String,V> next() {
return new Map.Entry<String,V>() {
String k = i.next();
public String getKey() { return k; }
public V getValue() { return get(k); }
public int hashCode() {
V v = get(k);
return (k.hashCode()
+ (v == null
? 0
: v.hashCode()));
}
public boolean equals(Object ob) {
if (ob == this)
return true;
if (!(ob instanceof Map.Entry))
return false;
Map.Entry<?,?> that = (Map.Entry<?,?>)ob;
return ((this.getKey() == null
? that.getKey() == null
: this.getKey()
.equals(that.getKey()))
&&
(this.getValue() == null
? that.getValue() == null
: this.getValue()
.equals(that.getValue())));
}
public V setValue(V v) {
throw new UnsupportedOperationException();
}
};
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* A Charset implementation for reading PropertyResourceBundle, in order
* for loading properties files. This first tries to load the properties
* file with UTF-8 encoding). If it fails, then load the file with ISO-8859-1
*/
public class PropertyResourceBundleCharset extends Charset {
private boolean strictUTF8 = false;
public PropertyResourceBundleCharset(boolean strictUTF8) {
this(PropertyResourceBundleCharset.class.getCanonicalName(), null);
this.strictUTF8 = strictUTF8;
}
public PropertyResourceBundleCharset(String canonicalName, String[] aliases) {
super(canonicalName, aliases);
}
@Override
public boolean contains(Charset cs) {
return false;
}
@Override
public CharsetDecoder newDecoder() {
return new PropertiesFileDecoder(this, 1.0f, 1.0f);
}
@Override
public CharsetEncoder newEncoder() {
throw new UnsupportedOperationException("Encoding is not supported");
}
private final class PropertiesFileDecoder extends CharsetDecoder {
private CharsetDecoder cdUTF_8 = StandardCharsets.UTF_8.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
private CharsetDecoder cdISO_8859_1 = null;
protected PropertiesFileDecoder(Charset cs,
float averageCharsPerByte, float maxCharsPerByte) {
super(cs, averageCharsPerByte, maxCharsPerByte);
}
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
if (Objects.nonNull(cdISO_8859_1)) {
return cdISO_8859_1.decode(in, out, false);
}
in.mark();
out.mark();
CoderResult cr = cdUTF_8.decode(in, out, false);
if (cr.isUnderflow() || cr.isOverflow() ||
PropertyResourceBundleCharset.this.strictUTF8) {
return cr;
}
// Invalid or unmappable UTF-8 sequence detected.
// Switching to the ISO 8859-1 decorder.
assert cr.isMalformed() || cr.isUnmappable();
in.reset();
out.reset();
cdISO_8859_1 = StandardCharsets.ISO_8859_1.newDecoder();
return cdISO_8859_1.decode(in, out, false);
}
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Implements an Enumeration that combines elements from a Set and
* an Enumeration. Used by ListResourceBundle and PropertyResourceBundle.
*/
public class ResourceBundleEnumeration implements Enumeration<String> {
Set<String> set;
Iterator<String> iterator;
Enumeration<String> enumeration; // may remain null
/**
* Constructs a resource bundle enumeration.
* @param set an set providing some elements of the enumeration
* @param enumeration an enumeration providing more elements of the enumeration.
* enumeration may be null.
*/
public ResourceBundleEnumeration(Set<String> set, Enumeration<String> enumeration) {
this.set = set;
this.iterator = set.iterator();
this.enumeration = enumeration;
}
String next = null;
public boolean hasMoreElements() {
if (next == null) {
if (iterator.hasNext()) {
next = iterator.next();
} else if (enumeration != null) {
while (next == null && enumeration.hasMoreElements()) {
next = enumeration.nextElement();
if (set.contains(next)) {
next = null;
}
}
}
}
return next != null;
}
public String nextElement() {
if (hasMoreElements()) {
String result = next;
next = null;
return result;
} else {
throw new NoSuchElementException();
}
}
}

View file

@ -0,0 +1,398 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.Locale;
import java.util.TimeZone;
/**
* The <code>AbstractCalendar</code> class provides a framework for
* implementing a concrete calendar system.
*
* <p><a name="fixed_date"></a><B>Fixed Date</B><br>
*
* For implementing a concrete calendar system, each calendar must
* have the common date numbering, starting from midnight the onset of
* Monday, January 1, 1 (Gregorian). It is called a <I>fixed date</I>
* in this class. January 1, 1 (Gregorian) is fixed date 1. (See
* Nachum Dershowitz and Edward M. Reingold, <I>CALENDRICAL
* CALCULATION The Millennium Edition</I>, Section 1.2 for details.)
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public abstract class AbstractCalendar extends CalendarSystem {
// The constants assume no leap seconds support.
static final int SECOND_IN_MILLIS = 1000;
static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
// The number of days between January 1, 1 and January 1, 1970 (Gregorian)
static final int EPOCH_OFFSET = 719163;
private Era[] eras;
protected AbstractCalendar() {
}
public Era getEra(String eraName) {
if (eras != null) {
for (Era era : eras) {
if (era.getName().equals(eraName)) {
return era;
}
}
}
return null;
}
public Era[] getEras() {
Era[] e = null;
if (eras != null) {
e = new Era[eras.length];
System.arraycopy(eras, 0, e, 0, eras.length);
}
return e;
}
public void setEra(CalendarDate date, String eraName) {
if (eras == null) {
return; // should report an error???
}
for (int i = 0; i < eras.length; i++) {
Era e = eras[i];
if (e != null && e.getName().equals(eraName)) {
date.setEra(e);
return;
}
}
throw new IllegalArgumentException("unknown era name: " + eraName);
}
protected void setEras(Era[] eras) {
this.eras = eras;
}
public CalendarDate getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
public CalendarDate getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
public CalendarDate getCalendarDate(long millis, TimeZone zone) {
CalendarDate date = newCalendarDate(zone);
return getCalendarDate(millis, date);
}
public CalendarDate getCalendarDate(long millis, CalendarDate date) {
int ms = 0; // time of day
int zoneOffset = 0;
int saving = 0;
long days = 0; // fixed date
// adjust to local time if `date' has time zone.
TimeZone zi = date.getZone();
if (zi != null) {
int[] offsets = new int[2];
if (zi instanceof ZoneInfo) {
zoneOffset = ((ZoneInfo)zi).getOffsets(millis, offsets);
} else {
zoneOffset = zi.getOffset(millis);
offsets[0] = zi.getRawOffset();
offsets[1] = zoneOffset - offsets[0];
}
// We need to calculate the given millis and time zone
// offset separately for java.util.GregorianCalendar
// compatibility. (i.e., millis + zoneOffset could cause
// overflow or underflow, which must be avoided.) Usually
// days should be 0 and ms is in the range of -13:00 to
// +14:00. However, we need to deal with extreme cases.
days = zoneOffset / DAY_IN_MILLIS;
ms = zoneOffset % DAY_IN_MILLIS;
saving = offsets[1];
}
date.setZoneOffset(zoneOffset);
date.setDaylightSaving(saving);
days += millis / DAY_IN_MILLIS;
ms += (int) (millis % DAY_IN_MILLIS);
if (ms >= DAY_IN_MILLIS) {
// at most ms is (DAY_IN_MILLIS - 1) * 2.
ms -= DAY_IN_MILLIS;
++days;
} else {
// at most ms is (1 - DAY_IN_MILLIS) * 2. Adding one
// DAY_IN_MILLIS results in still negative.
while (ms < 0) {
ms += DAY_IN_MILLIS;
--days;
}
}
// convert to fixed date (offset from Jan. 1, 1 (Gregorian))
days += EPOCH_OFFSET;
// calculate date fields from the fixed date
getCalendarDateFromFixedDate(date, days);
// calculate time fields from the time of day
setTimeOfDay(date, ms);
date.setLeapYear(isLeapYear(date));
date.setNormalized(true);
return date;
}
public long getTime(CalendarDate date) {
long gd = getFixedDate(date);
long ms = (gd - EPOCH_OFFSET) * DAY_IN_MILLIS + getTimeOfDay(date);
int zoneOffset = 0;
TimeZone zi = date.getZone();
if (zi != null) {
if (date.isNormalized()) {
return ms - date.getZoneOffset();
}
// adjust time zone and daylight saving
int[] offsets = new int[2];
if (date.isStandardTime()) {
// 1) 2:30am during starting-DST transition is
// intrepreted as 2:30am ST
// 2) 5:00pm during DST is still interpreted as 5:00pm ST
// 3) 1:30am during ending-DST transition is interpreted
// as 1:30am ST (after transition)
if (zi instanceof ZoneInfo) {
((ZoneInfo)zi).getOffsetsByStandard(ms, offsets);
zoneOffset = offsets[0];
} else {
zoneOffset = zi.getOffset(ms - zi.getRawOffset());
}
} else {
// 1) 2:30am during starting-DST transition is
// intrepreted as 3:30am DT
// 2) 5:00pm during DST is intrepreted as 5:00pm DT
// 3) 1:30am during ending-DST transition is interpreted
// as 1:30am DT/0:30am ST (before transition)
if (zi instanceof ZoneInfo) {
zoneOffset = ((ZoneInfo)zi).getOffsetsByWall(ms, offsets);
} else {
zoneOffset = zi.getOffset(ms - zi.getRawOffset());
}
}
}
ms -= zoneOffset;
getCalendarDate(ms, date);
return ms;
}
protected long getTimeOfDay(CalendarDate date) {
long fraction = date.getTimeOfDay();
if (fraction != CalendarDate.TIME_UNDEFINED) {
return fraction;
}
fraction = getTimeOfDayValue(date);
date.setTimeOfDay(fraction);
return fraction;
}
public long getTimeOfDayValue(CalendarDate date) {
long fraction = date.getHours();
fraction *= 60;
fraction += date.getMinutes();
fraction *= 60;
fraction += date.getSeconds();
fraction *= 1000;
fraction += date.getMillis();
return fraction;
}
public CalendarDate setTimeOfDay(CalendarDate cdate, int fraction) {
if (fraction < 0) {
throw new IllegalArgumentException();
}
boolean normalizedState = cdate.isNormalized();
int time = fraction;
int hours = time / HOUR_IN_MILLIS;
time %= HOUR_IN_MILLIS;
int minutes = time / MINUTE_IN_MILLIS;
time %= MINUTE_IN_MILLIS;
int seconds = time / SECOND_IN_MILLIS;
time %= SECOND_IN_MILLIS;
cdate.setHours(hours);
cdate.setMinutes(minutes);
cdate.setSeconds(seconds);
cdate.setMillis(time);
cdate.setTimeOfDay(fraction);
if (hours < 24 && normalizedState) {
// If this time of day setting doesn't affect the date,
// then restore the normalized state.
cdate.setNormalized(normalizedState);
}
return cdate;
}
/**
* Returns 7 in this default implementation.
*
* @return 7
*/
public int getWeekLength() {
return 7;
}
protected abstract boolean isLeapYear(CalendarDate date);
public CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, CalendarDate date) {
CalendarDate ndate = (CalendarDate) date.clone();
normalize(ndate);
long fd = getFixedDate(ndate);
long nfd;
if (nth > 0) {
nfd = 7 * nth + getDayOfWeekDateBefore(fd, dayOfWeek);
} else {
nfd = 7 * nth + getDayOfWeekDateAfter(fd, dayOfWeek);
}
getCalendarDateFromFixedDate(ndate, nfd);
return ndate;
}
/**
* Returns a date of the given day of week before the given fixed
* date.
*
* @param fixedDate the fixed date
* @param dayOfWeek the day of week
* @return the calculated date
*/
static long getDayOfWeekDateBefore(long fixedDate, int dayOfWeek) {
return getDayOfWeekDateOnOrBefore(fixedDate - 1, dayOfWeek);
}
/**
* Returns a date of the given day of week that is closest to and
* after the given fixed date.
*
* @param fixedDate the fixed date
* @param dayOfWeek the day of week
* @return the calculated date
*/
static long getDayOfWeekDateAfter(long fixedDate, int dayOfWeek) {
return getDayOfWeekDateOnOrBefore(fixedDate + 7, dayOfWeek);
}
/**
* Returns a date of the given day of week on or before the given fixed
* date.
*
* @param fixedDate the fixed date
* @param dayOfWeek the day of week
* @return the calculated date
*/
// public for java.util.GregorianCalendar
public static long getDayOfWeekDateOnOrBefore(long fixedDate, int dayOfWeek) {
long fd = fixedDate - (dayOfWeek - 1);
if (fd >= 0) {
return fixedDate - (fd % 7);
}
return fixedDate - CalendarUtils.mod(fd, 7);
}
/**
* Returns the fixed date calculated with the specified calendar
* date. If the specified date is not normalized, its date fields
* are normalized.
*
* @param date a <code>CalendarDate</code> with which the fixed
* date is calculated
* @return the calculated fixed date
* @see AbstractCalendar.html#fixed_date
*/
protected abstract long getFixedDate(CalendarDate date);
/**
* Calculates calendar fields from the specified fixed date. This
* method stores the calculated calendar field values in the specified
* <code>CalendarDate</code>.
*
* @param date a <code>CalendarDate</code> to stored the
* calculated calendar fields.
* @param fixedDate a fixed date to calculate calendar fields
* @see AbstractCalendar.html#fixed_date
*/
protected abstract void getCalendarDateFromFixedDate(CalendarDate date,
long fixedDate);
public boolean validateTime(CalendarDate date) {
int t = date.getHours();
if (t < 0 || t >= 24) {
return false;
}
t = date.getMinutes();
if (t < 0 || t >= 60) {
return false;
}
t = date.getSeconds();
// TODO: Leap second support.
if (t < 0 || t >= 60) {
return false;
}
t = date.getMillis();
if (t < 0 || t >= 1000) {
return false;
}
return true;
}
int normalizeTime(CalendarDate date) {
long fraction = getTimeOfDay(date);
long days = 0;
if (fraction >= DAY_IN_MILLIS) {
days = fraction / DAY_IN_MILLIS;
fraction %= DAY_IN_MILLIS;
} else if (fraction < 0) {
days = CalendarUtils.floorDivide(fraction, DAY_IN_MILLIS);
if (days != 0) {
fraction -= DAY_IN_MILLIS * days; // mod(fraction, DAY_IN_MILLIS)
}
}
if (days != 0) {
date.setTimeOfDay(fraction);
}
date.setMillis((int)(fraction % 1000));
fraction /= 1000;
date.setSeconds((int)(fraction % 60));
fraction /= 60;
date.setMinutes((int)(fraction % 60));
date.setHours((int)(fraction / 60));
return (int)days;
}
}

View file

@ -0,0 +1,537 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.TimeZone;
/**
* The {@code BaseCalendar} provides basic calendar calculation
* functions to support the Julian, Gregorian, and Gregorian-based
* calendar systems.
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public abstract class BaseCalendar extends AbstractCalendar {
public static final int JANUARY = 1;
public static final int FEBRUARY = 2;
public static final int MARCH = 3;
public static final int APRIL = 4;
public static final int MAY = 5;
public static final int JUNE = 6;
public static final int JULY = 7;
public static final int AUGUST = 8;
public static final int SEPTEMBER = 9;
public static final int OCTOBER = 10;
public static final int NOVEMBER = 11;
public static final int DECEMBER = 12;
// day of week constants
public static final int SUNDAY = 1;
public static final int MONDAY = 2;
public static final int TUESDAY = 3;
public static final int WEDNESDAY = 4;
public static final int THURSDAY = 5;
public static final int FRIDAY = 6;
public static final int SATURDAY = 7;
// The base Gregorian year of FIXED_DATES[]
private static final int BASE_YEAR = 1970;
// Pre-calculated fixed dates of January 1 from BASE_YEAR
// (Gregorian). This table covers all the years that can be
// supported by the POSIX time_t (32-bit) after the Epoch. Note
// that the data type is int[].
private static final int[] FIXED_DATES = {
719163, // 1970
719528, // 1971
719893, // 1972
720259, // 1973
720624, // 1974
720989, // 1975
721354, // 1976
721720, // 1977
722085, // 1978
722450, // 1979
722815, // 1980
723181, // 1981
723546, // 1982
723911, // 1983
724276, // 1984
724642, // 1985
725007, // 1986
725372, // 1987
725737, // 1988
726103, // 1989
726468, // 1990
726833, // 1991
727198, // 1992
727564, // 1993
727929, // 1994
728294, // 1995
728659, // 1996
729025, // 1997
729390, // 1998
729755, // 1999
730120, // 2000
730486, // 2001
730851, // 2002
731216, // 2003
731581, // 2004
731947, // 2005
732312, // 2006
732677, // 2007
733042, // 2008
733408, // 2009
733773, // 2010
734138, // 2011
734503, // 2012
734869, // 2013
735234, // 2014
735599, // 2015
735964, // 2016
736330, // 2017
736695, // 2018
737060, // 2019
737425, // 2020
737791, // 2021
738156, // 2022
738521, // 2023
738886, // 2024
739252, // 2025
739617, // 2026
739982, // 2027
740347, // 2028
740713, // 2029
741078, // 2030
741443, // 2031
741808, // 2032
742174, // 2033
742539, // 2034
742904, // 2035
743269, // 2036
743635, // 2037
744000, // 2038
744365, // 2039
};
public abstract static class Date extends CalendarDate {
protected Date() {
super();
}
protected Date(TimeZone zone) {
super(zone);
}
public Date setNormalizedDate(int normalizedYear, int month, int dayOfMonth) {
setNormalizedYear(normalizedYear);
setMonth(month).setDayOfMonth(dayOfMonth);
return this;
}
public abstract int getNormalizedYear();
public abstract void setNormalizedYear(int normalizedYear);
// Cache for the fixed date of January 1 and year length of the
// cachedYear. A simple benchmark showed 7% performance
// improvement with >90% cache hit. The initial values are for Gregorian.
int cachedYear = 2004;
long cachedFixedDateJan1 = 731581L;
long cachedFixedDateNextJan1 = cachedFixedDateJan1 + 366;
protected final boolean hit(int year) {
return year == cachedYear;
}
protected final boolean hit(long fixedDate) {
return (fixedDate >= cachedFixedDateJan1 &&
fixedDate < cachedFixedDateNextJan1);
}
protected int getCachedYear() {
return cachedYear;
}
protected long getCachedJan1() {
return cachedFixedDateJan1;
}
protected void setCache(int year, long jan1, int len) {
cachedYear = year;
cachedFixedDateJan1 = jan1;
cachedFixedDateNextJan1 = jan1 + len;
}
}
public boolean validate(CalendarDate date) {
Date bdate = (Date) date;
if (bdate.isNormalized()) {
return true;
}
int month = bdate.getMonth();
if (month < JANUARY || month > DECEMBER) {
return false;
}
int d = bdate.getDayOfMonth();
if (d <= 0 || d > getMonthLength(bdate.getNormalizedYear(), month)) {
return false;
}
int dow = bdate.getDayOfWeek();
if (dow != Date.FIELD_UNDEFINED && dow != getDayOfWeek(bdate)) {
return false;
}
if (!validateTime(date)) {
return false;
}
bdate.setNormalized(true);
return true;
}
public boolean normalize(CalendarDate date) {
if (date.isNormalized()) {
return true;
}
Date bdate = (Date) date;
TimeZone zi = bdate.getZone();
// If the date has a time zone, then we need to recalculate
// the calendar fields. Let getTime() do it.
if (zi != null) {
getTime(date);
return true;
}
int days = normalizeTime(bdate);
normalizeMonth(bdate);
long d = (long)bdate.getDayOfMonth() + days;
int m = bdate.getMonth();
int y = bdate.getNormalizedYear();
int ml = getMonthLength(y, m);
if (!(d > 0 && d <= ml)) {
if (d <= 0 && d > -28) {
ml = getMonthLength(y, --m);
d += ml;
bdate.setDayOfMonth((int) d);
if (m == 0) {
m = DECEMBER;
bdate.setNormalizedYear(y - 1);
}
bdate.setMonth(m);
} else if (d > ml && d < (ml + 28)) {
d -= ml;
++m;
bdate.setDayOfMonth((int)d);
if (m > DECEMBER) {
bdate.setNormalizedYear(y + 1);
m = JANUARY;
}
bdate.setMonth(m);
} else {
long fixedDate = d + getFixedDate(y, m, 1, bdate) - 1L;
getCalendarDateFromFixedDate(bdate, fixedDate);
}
} else {
bdate.setDayOfWeek(getDayOfWeek(bdate));
}
date.setLeapYear(isLeapYear(bdate.getNormalizedYear()));
date.setZoneOffset(0);
date.setDaylightSaving(0);
bdate.setNormalized(true);
return true;
}
void normalizeMonth(CalendarDate date) {
Date bdate = (Date) date;
int year = bdate.getNormalizedYear();
long month = bdate.getMonth();
if (month <= 0) {
long xm = 1L - month;
year -= (int)((xm / 12) + 1);
month = 13 - (xm % 12);
bdate.setNormalizedYear(year);
bdate.setMonth((int) month);
} else if (month > DECEMBER) {
year += (int)((month - 1) / 12);
month = ((month - 1)) % 12 + 1;
bdate.setNormalizedYear(year);
bdate.setMonth((int) month);
}
}
/**
* Returns 366 if the specified date is in a leap year, or 365
* otherwise This method does not perform the normalization with
* the specified {@code CalendarDate}. The
* {@code CalendarDate} must be normalized to get a correct
* value.
*
* @param date a {@code CalendarDate}
* @return a year length in days
* @throws ClassCastException if the specified date is not a
* {@link BaseCalendar.Date}
*/
public int getYearLength(CalendarDate date) {
return isLeapYear(((Date)date).getNormalizedYear()) ? 366 : 365;
}
public int getYearLengthInMonths(CalendarDate date) {
return 12;
}
static final int[] DAYS_IN_MONTH
// 12 1 2 3 4 5 6 7 8 9 10 11 12
= { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static final int[] ACCUMULATED_DAYS_IN_MONTH
// 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1
= { -30, 0, 31, 59, 90,120,151,181,212,243, 273, 304, 334};
static final int[] ACCUMULATED_DAYS_IN_MONTH_LEAP
// 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1
= { -30, 0, 31, 59+1, 90+1,120+1,151+1,181+1,212+1,243+1, 273+1, 304+1, 334+1};
public int getMonthLength(CalendarDate date) {
Date gdate = (Date) date;
int month = gdate.getMonth();
if (month < JANUARY || month > DECEMBER) {
throw new IllegalArgumentException("Illegal month value: " + month);
}
return getMonthLength(gdate.getNormalizedYear(), month);
}
// accepts 0 (December in the previous year) to 12.
private int getMonthLength(int year, int month) {
int days = DAYS_IN_MONTH[month];
if (month == FEBRUARY && isLeapYear(year)) {
days++;
}
return days;
}
public long getDayOfYear(CalendarDate date) {
return getDayOfYear(((Date)date).getNormalizedYear(),
date.getMonth(),
date.getDayOfMonth());
}
final long getDayOfYear(int year, int month, int dayOfMonth) {
return (long) dayOfMonth
+ (isLeapYear(year) ?
ACCUMULATED_DAYS_IN_MONTH_LEAP[month] : ACCUMULATED_DAYS_IN_MONTH[month]);
}
// protected
public long getFixedDate(CalendarDate date) {
if (!date.isNormalized()) {
normalizeMonth(date);
}
return getFixedDate(((Date)date).getNormalizedYear(),
date.getMonth(),
date.getDayOfMonth(),
(BaseCalendar.Date) date);
}
// public for java.util.GregorianCalendar
public long getFixedDate(int year, int month, int dayOfMonth, BaseCalendar.Date cache) {
boolean isJan1 = month == JANUARY && dayOfMonth == 1;
// Look up the one year cache
if (cache != null && cache.hit(year)) {
if (isJan1) {
return cache.getCachedJan1();
}
return cache.getCachedJan1() + getDayOfYear(year, month, dayOfMonth) - 1;
}
// Look up the pre-calculated fixed date table
int n = year - BASE_YEAR;
if (n >= 0 && n < FIXED_DATES.length) {
long jan1 = FIXED_DATES[n];
if (cache != null) {
cache.setCache(year, jan1, isLeapYear(year) ? 366 : 365);
}
return isJan1 ? jan1 : jan1 + getDayOfYear(year, month, dayOfMonth) - 1;
}
long prevyear = (long)year - 1;
long days = dayOfMonth;
if (prevyear >= 0) {
days += (365 * prevyear)
+ (prevyear / 4)
- (prevyear / 100)
+ (prevyear / 400)
+ ((367 * month - 362) / 12);
} else {
days += (365 * prevyear)
+ CalendarUtils.floorDivide(prevyear, 4)
- CalendarUtils.floorDivide(prevyear, 100)
+ CalendarUtils.floorDivide(prevyear, 400)
+ CalendarUtils.floorDivide((367 * month - 362), 12);
}
if (month > FEBRUARY) {
days -= isLeapYear(year) ? 1 : 2;
}
// If it's January 1, update the cache.
if (cache != null && isJan1) {
cache.setCache(year, days, isLeapYear(year) ? 366 : 365);
}
return days;
}
/**
* Calculates calendar fields and store them in the specified
* {@code CalendarDate}.
*/
// should be 'protected'
public void getCalendarDateFromFixedDate(CalendarDate date,
long fixedDate) {
Date gdate = (Date) date;
int year;
long jan1;
boolean isLeap;
if (gdate.hit(fixedDate)) {
year = gdate.getCachedYear();
jan1 = gdate.getCachedJan1();
isLeap = isLeapYear(year);
} else {
// Looking up FIXED_DATES[] here didn't improve performance
// much. So we calculate year and jan1. getFixedDate()
// will look up FIXED_DATES[] actually.
year = getGregorianYearFromFixedDate(fixedDate);
jan1 = getFixedDate(year, JANUARY, 1, null);
isLeap = isLeapYear(year);
// Update the cache data
gdate.setCache (year, jan1, isLeap ? 366 : 365);
}
int priorDays = (int)(fixedDate - jan1);
long mar1 = jan1 + 31 + 28;
if (isLeap) {
++mar1;
}
if (fixedDate >= mar1) {
priorDays += isLeap ? 1 : 2;
}
int month = 12 * priorDays + 373;
if (month > 0) {
month /= 367;
} else {
month = CalendarUtils.floorDivide(month, 367);
}
long month1 = jan1 + ACCUMULATED_DAYS_IN_MONTH[month];
if (isLeap && month >= MARCH) {
++month1;
}
int dayOfMonth = (int)(fixedDate - month1) + 1;
int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate);
assert dayOfWeek > 0 : "negative day of week " + dayOfWeek;
gdate.setNormalizedYear(year);
gdate.setMonth(month);
gdate.setDayOfMonth(dayOfMonth);
gdate.setDayOfWeek(dayOfWeek);
gdate.setLeapYear(isLeap);
gdate.setNormalized(true);
}
/**
* Returns the day of week of the given Gregorian date.
*/
public int getDayOfWeek(CalendarDate date) {
long fixedDate = getFixedDate(date);
return getDayOfWeekFromFixedDate(fixedDate);
}
public static final int getDayOfWeekFromFixedDate(long fixedDate) {
// The fixed day 1 (January 1, 1 Gregorian) is Monday.
if (fixedDate >= 0) {
return (int)(fixedDate % 7) + SUNDAY;
}
return (int)CalendarUtils.mod(fixedDate, 7) + SUNDAY;
}
public int getYearFromFixedDate(long fixedDate) {
return getGregorianYearFromFixedDate(fixedDate);
}
/**
* Returns the Gregorian year number of the given fixed date.
*/
final int getGregorianYearFromFixedDate(long fixedDate) {
long d0;
int d1, d2, d3, d4;
int n400, n100, n4, n1;
int year;
if (fixedDate > 0) {
d0 = fixedDate - 1;
n400 = (int)(d0 / 146097);
d1 = (int)(d0 % 146097);
n100 = d1 / 36524;
d2 = d1 % 36524;
n4 = d2 / 1461;
d3 = d2 % 1461;
n1 = d3 / 365;
d4 = (d3 % 365) + 1;
} else {
d0 = fixedDate - 1;
n400 = (int)CalendarUtils.floorDivide(d0, 146097L);
d1 = (int)CalendarUtils.mod(d0, 146097L);
n100 = CalendarUtils.floorDivide(d1, 36524);
d2 = CalendarUtils.mod(d1, 36524);
n4 = CalendarUtils.floorDivide(d2, 1461);
d3 = CalendarUtils.mod(d2, 1461);
n1 = CalendarUtils.floorDivide(d3, 365);
d4 = CalendarUtils.mod(d3, 365) + 1;
}
year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
if (!(n100 == 4 || n1 == 4)) {
++year;
}
return year;
}
/**
* @return true if the specified year is a Gregorian leap year, or
* false otherwise.
* @see BaseCalendar#isGregorianLeapYear
*/
protected boolean isLeapYear(CalendarDate date) {
return isLeapYear(((Date)date).getNormalizedYear());
}
boolean isLeapYear(int normalizedYear) {
return CalendarUtils.isGregorianLeapYear(normalizedYear);
}
}

View file

@ -0,0 +1,505 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.lang.Cloneable;
import java.util.Locale;
import java.util.TimeZone;
/**
* The <code>CalendarDate</code> class represents a specific instant
* in time by calendar date and time fields that are multiple cycles
* in different time unites. The semantics of each calendar field is
* given by a concrete calendar system rather than this
* <code>CalendarDate</code> class that holds calendar field values
* without interpreting them. Therefore, this class can be used to
* represent an amount of time, such as 2 years and 3 months.
*
* <p>A <code>CalendarDate</code> instance can be created by calling
* the <code>newCalendarDate</code> or <code>getCalendarDate</code>
* methods in <code>CalendarSystem</code>. A
* <code>CalendarSystem</code> instance is obtained by calling one of
* the factory methods in <code>CalendarSystem</code>. Manipulations
* of calendar dates must be handled by the calendar system by which
* <code>CalendarDate</code> instances have been created.
*
* <p>Some calendar fields can be modified through method calls. Any
* modification of a calendar field brings the state of a
* <code>CalendarDate</code> to <I>not normalized</I>. The
* normalization must be performed to make all the calendar fields
* consistent with a calendar system.
*
* <p>The <code>protected</code> methods are intended to be used for
* implementing a concrete calendar system, not for general use as an
* API.
*
* @see CalendarSystem
* @author Masayoshi Okutsu
* @since 1.5
*/
public abstract class CalendarDate implements Cloneable {
public static final int FIELD_UNDEFINED = Integer.MIN_VALUE;
public static final long TIME_UNDEFINED = Long.MIN_VALUE;
private Era era;
private int year;
private int month;
private int dayOfMonth;
private int dayOfWeek = FIELD_UNDEFINED;
private boolean leapYear;
private int hours;
private int minutes;
private int seconds;
private int millis; // fractional part of the second
private long fraction; // time of day value in millisecond
private boolean normalized;
private TimeZone zoneinfo;
private int zoneOffset;
private int daylightSaving;
private boolean forceStandardTime;
private Locale locale;
protected CalendarDate() {
this(TimeZone.getDefault());
}
protected CalendarDate(TimeZone zone) {
zoneinfo = zone;
}
public Era getEra() {
return era;
}
/**
* Sets the era of the date to the specified era. The default
* implementation of this method accepts any Era value, including
* <code>null</code>.
*
* @exception NullPointerException if the calendar system for this
* <code>CalendarDate</code> requires eras and the specified era
* is null.
* @exception IllegalArgumentException if the specified
* <code>era</code> is unknown to the calendar
* system for this <code>CalendarDate</code>.
*/
public CalendarDate setEra(Era era) {
if (this.era == era) {
return this;
}
this.era = era;
normalized = false;
return this;
}
public int getYear() {
return year;
}
public CalendarDate setYear(int year) {
if (this.year != year) {
this.year = year;
normalized = false;
}
return this;
}
public CalendarDate addYear(int n) {
if (n != 0) {
year += n;
normalized = false;
}
return this;
}
/**
* Returns whether the year represented by this
* <code>CalendarDate</code> is a leap year. If leap years are
* not applicable to the calendar system, this method always
* returns <code>false</code>.
*
* <p>If this <code>CalendarDate</code> hasn't been normalized,
* <code>false</code> is returned. The normalization must be
* performed to retrieve the correct leap year information.
*
* @return <code>true</code> if this <code>CalendarDate</code> is
* normalized and the year of this <code>CalendarDate</code> is a
* leap year, or <code>false</code> otherwise.
* @see BaseCalendar#isGregorianLeapYear
*/
public boolean isLeapYear() {
return leapYear;
}
void setLeapYear(boolean leapYear) {
this.leapYear = leapYear;
}
public int getMonth() {
return month;
}
public CalendarDate setMonth(int month) {
if (this.month != month) {
this.month = month;
normalized = false;
}
return this;
}
public CalendarDate addMonth(int n) {
if (n != 0) {
month += n;
normalized = false;
}
return this;
}
public int getDayOfMonth() {
return dayOfMonth;
}
public CalendarDate setDayOfMonth(int date) {
if (dayOfMonth != date) {
dayOfMonth = date;
normalized = false;
}
return this;
}
public CalendarDate addDayOfMonth(int n) {
if (n != 0) {
dayOfMonth += n;
normalized = false;
}
return this;
}
/**
* Returns the day of week value. If this CalendarDate is not
* normalized, {@link #FIELD_UNDEFINED} is returned.
*
* @return day of week or {@link #FIELD_UNDEFINED}
*/
public int getDayOfWeek() {
if (!isNormalized()) {
dayOfWeek = FIELD_UNDEFINED;
}
return dayOfWeek;
}
public int getHours() {
return hours;
}
public CalendarDate setHours(int hours) {
if (this.hours != hours) {
this.hours = hours;
normalized = false;
}
return this;
}
public CalendarDate addHours(int n) {
if (n != 0) {
hours += n;
normalized = false;
}
return this;
}
public int getMinutes() {
return minutes;
}
public CalendarDate setMinutes(int minutes) {
if (this.minutes != minutes) {
this.minutes = minutes;
normalized = false;
}
return this;
}
public CalendarDate addMinutes(int n) {
if (n != 0) {
minutes += n;
normalized = false;
}
return this;
}
public int getSeconds() {
return seconds;
}
public CalendarDate setSeconds(int seconds) {
if (this.seconds != seconds) {
this.seconds = seconds;
normalized = false;
}
return this;
}
public CalendarDate addSeconds(int n) {
if (n != 0) {
seconds += n;
normalized = false;
}
return this;
}
public int getMillis() {
return millis;
}
public CalendarDate setMillis(int millis) {
if (this.millis != millis) {
this.millis = millis;
normalized = false;
}
return this;
}
public CalendarDate addMillis(int n) {
if (n != 0) {
millis += n;
normalized = false;
}
return this;
}
public long getTimeOfDay() {
if (!isNormalized()) {
return fraction = TIME_UNDEFINED;
}
return fraction;
}
public CalendarDate setDate(int year, int month, int dayOfMonth) {
setYear(year);
setMonth(month);
setDayOfMonth(dayOfMonth);
return this;
}
public CalendarDate addDate(int year, int month, int dayOfMonth) {
addYear(year);
addMonth(month);
addDayOfMonth(dayOfMonth);
return this;
}
public CalendarDate setTimeOfDay(int hours, int minutes, int seconds, int millis) {
setHours(hours);
setMinutes(minutes);
setSeconds(seconds);
setMillis(millis);
return this;
}
public CalendarDate addTimeOfDay(int hours, int minutes, int seconds, int millis) {
addHours(hours);
addMinutes(minutes);
addSeconds(seconds);
addMillis(millis);
return this;
}
protected void setTimeOfDay(long fraction) {
this.fraction = fraction;
}
public boolean isNormalized() {
return normalized;
}
public boolean isStandardTime() {
return forceStandardTime;
}
public void setStandardTime(boolean standardTime) {
forceStandardTime = standardTime;
}
public boolean isDaylightTime() {
if (isStandardTime()) {
return false;
}
return daylightSaving != 0;
}
protected void setLocale(Locale loc) {
locale = loc;
}
public TimeZone getZone() {
return zoneinfo;
}
public CalendarDate setZone(TimeZone zoneinfo) {
this.zoneinfo = zoneinfo;
return this;
}
/**
* Returns whether the specified date is the same date of this
* <code>CalendarDate</code>. The time of the day fields are
* ignored for the comparison.
*/
public boolean isSameDate(CalendarDate date) {
return getDayOfWeek() == date.getDayOfWeek()
&& getMonth() == date.getMonth()
&& getYear() == date.getYear()
&& getEra() == date.getEra();
}
public boolean equals(Object obj) {
if (!(obj instanceof CalendarDate)) {
return false;
}
CalendarDate that = (CalendarDate) obj;
if (isNormalized() != that.isNormalized()) {
return false;
}
boolean hasZone = zoneinfo != null;
boolean thatHasZone = that.zoneinfo != null;
if (hasZone != thatHasZone) {
return false;
}
if (hasZone && !zoneinfo.equals(that.zoneinfo)) {
return false;
}
return (getEra() == that.getEra()
&& year == that.year
&& month == that.month
&& dayOfMonth == that.dayOfMonth
&& hours == that.hours
&& minutes == that.minutes
&& seconds == that.seconds
&& millis == that.millis
&& zoneOffset == that.zoneOffset);
}
public int hashCode() {
// a pseudo (local standard) time stamp value in milliseconds
// from the Epoch, assuming Gregorian calendar fields.
long hash = ((((((long)year - 1970) * 12) + (month - 1)) * 30) + dayOfMonth) * 24;
hash = ((((((hash + hours) * 60) + minutes) * 60) + seconds) * 1000) + millis;
hash -= zoneOffset;
int normalized = isNormalized() ? 1 : 0;
int era = 0;
Era e = getEra();
if (e != null) {
era = e.hashCode();
}
int zone = zoneinfo != null ? zoneinfo.hashCode() : 0;
return (int) hash * (int)(hash >> 32) ^ era ^ normalized ^ zone;
}
/**
* Returns a copy of this <code>CalendarDate</code>. The
* <code>TimeZone</code> object, if any, is not cloned.
*
* @return a copy of this <code>CalendarDate</code>
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen
throw new InternalError(e);
}
}
/**
* Converts calendar date values to a <code>String</code> in the
* following format.
* <pre>
* yyyy-MM-dd'T'HH:mm:ss.SSSz
* </pre>
*
* @see java.text.SimpleDateFormat
*/
public String toString() {
StringBuilder sb = new StringBuilder();
CalendarUtils.sprintf0d(sb, year, 4).append('-');
CalendarUtils.sprintf0d(sb, month, 2).append('-');
CalendarUtils.sprintf0d(sb, dayOfMonth, 2).append('T');
CalendarUtils.sprintf0d(sb, hours, 2).append(':');
CalendarUtils.sprintf0d(sb, minutes, 2).append(':');
CalendarUtils.sprintf0d(sb, seconds, 2).append('.');
CalendarUtils.sprintf0d(sb, millis, 3);
if (zoneOffset == 0) {
sb.append('Z');
} else if (zoneOffset != FIELD_UNDEFINED) {
int offset;
char sign;
if (zoneOffset > 0) {
offset = zoneOffset;
sign = '+';
} else {
offset = -zoneOffset;
sign = '-';
}
offset /= 60000;
sb.append(sign);
CalendarUtils.sprintf0d(sb, offset / 60, 2);
CalendarUtils.sprintf0d(sb, offset % 60, 2);
} else {
sb.append(" local time");
}
return sb.toString();
}
protected void setDayOfWeek(int dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
protected void setNormalized(boolean normalized) {
this.normalized = normalized;
}
public int getZoneOffset() {
return zoneOffset;
}
protected void setZoneOffset(int offset) {
zoneOffset = offset;
}
public int getDaylightSaving() {
return daylightSaving;
}
protected void setDaylightSaving(int daylightSaving) {
this.daylightSaving = daylightSaving;
}
}

View file

@ -0,0 +1,351 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* <code>CalendarSystem</code> is an abstract class that defines the
* programming interface to deal with calendar date and time.
*
* <p><code>CalendarSystem</code> instances are singletons. For
* example, there exists only one Gregorian calendar instance in the
* Java runtime environment. A singleton instance can be obtained
* calling one of the static factory methods.
*
* <h4>CalendarDate</h4>
*
* <p>For the methods in a <code>CalendarSystem</code> that manipulate
* a <code>CalendarDate</code>, <code>CalendarDate</code>s that have
* been created by the <code>CalendarSystem</code> must be
* specified. Otherwise, the methods throw an exception. This is
* because, for example, a Chinese calendar date can't be understood
* by the Hebrew calendar system.
*
* <h4>Calendar names</h4>
*
* Each calendar system has a unique name to be identified. The Java
* runtime in this release supports the following calendar systems.
*
* <pre>
* Name Calendar System
* ---------------------------------------
* gregorian Gregorian Calendar
* julian Julian Calendar
* japanese Japanese Imperial Calendar
* </pre>
*
* @see CalendarDate
* @author Masayoshi Okutsu
* @since 1.5
*/
public abstract class CalendarSystem {
/////////////////////// Calendar Factory Methods /////////////////////////
private static volatile boolean initialized;
// Map of calendar names and calendar class names
private static ConcurrentMap<String, String> names;
// Map of calendar names and CalendarSystem instances
private static ConcurrentMap<String,CalendarSystem> calendars;
private static final String PACKAGE_NAME = "sun.util.calendar.";
private static final String[] namePairs = {
"gregorian", "Gregorian",
"japanese", "LocalGregorianCalendar",
"julian", "JulianCalendar",
/*
"hebrew", "HebrewCalendar",
"iso8601", "ISOCalendar",
"taiwanese", "LocalGregorianCalendar",
"thaibuddhist", "LocalGregorianCalendar",
*/
};
private static void initNames() {
ConcurrentMap<String,String> nameMap = new ConcurrentHashMap<>();
// Associate a calendar name with its class name and the
// calendar class name with its date class name.
StringBuilder clName = new StringBuilder();
for (int i = 0; i < namePairs.length; i += 2) {
clName.setLength(0);
String cl = clName.append(PACKAGE_NAME).append(namePairs[i+1]).toString();
nameMap.put(namePairs[i], cl);
}
synchronized (CalendarSystem.class) {
if (!initialized) {
names = nameMap;
calendars = new ConcurrentHashMap<>();
initialized = true;
}
}
}
private static final Gregorian GREGORIAN_INSTANCE = new Gregorian();
/**
* Returns the singleton instance of the <code>Gregorian</code>
* calendar system.
*
* @return the <code>Gregorian</code> instance
*/
public static Gregorian getGregorianCalendar() {
return GREGORIAN_INSTANCE;
}
/**
* Returns a <code>CalendarSystem</code> specified by the calendar
* name. The calendar name has to be one of the supported calendar
* names.
*
* @param calendarName the calendar name
* @return the <code>CalendarSystem</code> specified by
* <code>calendarName</code>, or null if there is no
* <code>CalendarSystem</code> associated with the given calendar name.
*/
public static CalendarSystem forName(String calendarName) {
if ("gregorian".equals(calendarName)) {
return GREGORIAN_INSTANCE;
}
if (!initialized) {
initNames();
}
CalendarSystem cal = calendars.get(calendarName);
if (cal != null) {
return cal;
}
String className = names.get(calendarName);
if (className == null) {
return null; // Unknown calendar name
}
if (className.endsWith("LocalGregorianCalendar")) {
// Create the specific kind of local Gregorian calendar system
cal = LocalGregorianCalendar.getLocalGregorianCalendar(calendarName);
} else {
try {
@SuppressWarnings("deprecation")
Object tmp = Class.forName(className).newInstance();
cal = (CalendarSystem) tmp;
} catch (Exception e) {
throw new InternalError(e);
}
}
if (cal == null) {
return null;
}
CalendarSystem cs = calendars.putIfAbsent(calendarName, cal);
return (cs == null) ? cal : cs;
}
//////////////////////////////// Calendar API //////////////////////////////////
/**
* Returns the name of this calendar system.
*/
public abstract String getName();
public abstract CalendarDate getCalendarDate();
/**
* Calculates calendar fields from the specified number of
* milliseconds since the Epoch, January 1, 1970 00:00:00 UTC
* (Gregorian). This method doesn't check overflow or underflow
* when adjusting the millisecond value (representing UTC) with
* the time zone offsets (i.e., the GMT offset and amount of
* daylight saving).
*
* @param millis the offset value in milliseconds from January 1,
* 1970 00:00:00 UTC (Gregorian).
* @return a <code>CalendarDate</code> instance that contains the
* calculated calendar field values.
*/
public abstract CalendarDate getCalendarDate(long millis);
public abstract CalendarDate getCalendarDate(long millis, CalendarDate date);
public abstract CalendarDate getCalendarDate(long millis, TimeZone zone);
/**
* Constructs a <code>CalendarDate</code> that is specific to this
* calendar system. All calendar fields have their initial
* values. The {@link TimeZone#getDefault() default time zone} is
* set to the instance.
*
* @return a <code>CalendarDate</code> instance that contains the initial
* calendar field values.
*/
public abstract CalendarDate newCalendarDate();
public abstract CalendarDate newCalendarDate(TimeZone zone);
/**
* Returns the number of milliseconds since the Epoch, January 1,
* 1970 00:00:00 UTC (Gregorian), represented by the specified
* <code>CalendarDate</code>.
*
* @param date the <code>CalendarDate</code> from which the time
* value is calculated
* @return the number of milliseconds since the Epoch.
*/
public abstract long getTime(CalendarDate date);
/**
* Returns the length in days of the specified year by
* <code>date</code>. This method does not perform the
* normalization with the specified <code>CalendarDate</code>. The
* <code>CalendarDate</code> must be normalized to get a correct
* value.
*/
public abstract int getYearLength(CalendarDate date);
/**
* Returns the number of months of the specified year. This method
* does not perform the normalization with the specified
* <code>CalendarDate</code>. The <code>CalendarDate</code> must
* be normalized to get a correct value.
*/
public abstract int getYearLengthInMonths(CalendarDate date);
/**
* Returns the length in days of the month specified by the calendar
* date. This method does not perform the normalization with the
* specified calendar date. The <code>CalendarDate</code> must
* be normalized to get a correct value.
*
* @param date the date from which the month value is obtained
* @return the number of days in the month
* @exception IllegalArgumentException if the specified calendar date
* doesn't have a valid month value in this calendar system.
*/
public abstract int getMonthLength(CalendarDate date); // no setter
/**
* Returns the length in days of a week in this calendar
* system. If this calendar system has multiple radix weeks, this
* method returns only one of them.
*/
public abstract int getWeekLength();
/**
* Returns the <code>Era</code> designated by the era name that
* has to be known to this calendar system. If no Era is
* applicable to this calendar system, null is returned.
*
* @param eraName the name of the era
* @return the <code>Era</code> designated by
* <code>eraName</code>, or <code>null</code> if no Era is
* applicable to this calendar system or the specified era name is
* not known to this calendar system.
*/
public abstract Era getEra(String eraName);
/**
* Returns valid <code>Era</code>s of this calendar system. The
* return value is sorted in the descendant order. (i.e., the first
* element of the returned array is the oldest era.) If no era is
* applicable to this calendar system, <code>null</code> is returned.
*
* @return an array of valid <code>Era</code>s, or
* <code>null</code> if no era is applicable to this calendar
* system.
*/
public abstract Era[] getEras();
/**
* @throws IllegalArgumentException if the specified era name is
* unknown to this calendar system.
* @see Era
*/
public abstract void setEra(CalendarDate date, String eraName);
/**
* Returns a <code>CalendarDate</code> of the n-th day of week
* which is on, after or before the specified date. For example, the
* first Sunday in April 2002 (Gregorian) can be obtained as
* below:
*
* <pre><code>
* Gregorian cal = CalendarSystem.getGregorianCalendar();
* CalendarDate date = cal.newCalendarDate();
* date.setDate(2004, cal.APRIL, 1);
* CalendarDate firstSun = cal.getNthDayOfWeek(1, cal.SUNDAY, date);
* // firstSun represents April 4, 2004.
* </code></pre>
*
* This method returns a new <code>CalendarDate</code> instance
* and doesn't modify the original date.
*
* @param nth specifies the n-th one. A positive number specifies
* <em>on or after</em> the <code>date</code>. A non-positive number
* specifies <em>on or before</em> the <code>date</code>.
* @param dayOfWeek the day of week
* @param date the date
* @return the date of the nth <code>dayOfWeek</code> after
* or before the specified <code>CalendarDate</code>
*/
public abstract CalendarDate getNthDayOfWeek(int nth, int dayOfWeek,
CalendarDate date);
public abstract CalendarDate setTimeOfDay(CalendarDate date, int timeOfDay);
/**
* Checks whether the calendar fields specified by <code>date</code>
* represents a valid date and time in this calendar system. If the
* given date is valid, <code>date</code> is marked as <em>normalized</em>.
*
* @param date the <code>CalendarDate</code> to be validated
* @return <code>true</code> if all the calendar fields are consistent,
* otherwise, <code>false</code> is returned.
* @exception NullPointerException if the specified
* <code>date</code> is <code>null</code>
*/
public abstract boolean validate(CalendarDate date);
/**
* Normalizes calendar fields in the specified
* <code>date</code>. Also all {@link CalendarDate#FIELD_UNDEFINED
* undefined} fields are set to correct values. The actual
* normalization process is calendar system dependent.
*
* @param date the calendar date to be validated
* @return <code>true</code> if all fields have been normalized;
* <code>false</code> otherwise.
* @exception NullPointerException if the specified
* <code>date</code> is <code>null</code>
*/
public abstract boolean normalize(CalendarDate date);
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.HashMap;
import java.util.Map;
public class CalendarUtils {
/**
* Returns whether the specified year is a leap year in the Gregorian
* calendar system.
*
* @param gregorianYear a Gregorian calendar year
* @return true if the given year is a leap year in the Gregorian
* calendar system.
* @see CalendarDate#isLeapYear
*/
public static final boolean isGregorianLeapYear(int gregorianYear) {
return (((gregorianYear % 4) == 0)
&& (((gregorianYear % 100) != 0) || ((gregorianYear % 400) == 0)));
}
/**
* Returns whether the specified year is a leap year in the Julian
* calendar system. The year number must be a normalized one
* (e.g., 45 B.C.E. is 1-45).
*
* @param normalizedJulianYear a normalized Julian calendar year
* @return true if the given year is a leap year in the Julian
* calendar system.
* @see CalendarDate#isLeapYear
*/
public static final boolean isJulianLeapYear(int normalizedJulianYear) {
return (normalizedJulianYear % 4) == 0;
}
/**
* Divides two integers and returns the floor of the quotient.
* For example, <code>floorDivide(-1, 4)</code> returns -1 while
* -1/4 is 0.
*
* @param n the numerator
* @param d a divisor that must be greater than 0
* @return the floor of the quotient
*/
public static final long floorDivide(long n, long d) {
return ((n >= 0) ?
(n / d) : (((n + 1L) / d) - 1L));
}
/**
* Divides two integers and returns the floor of the quotient.
* For example, <code>floorDivide(-1, 4)</code> returns -1 while
* -1/4 is 0.
*
* @param n the numerator
* @param d a divisor that must be greater than 0
* @return the floor of the quotient
*/
public static final int floorDivide(int n, int d) {
return ((n >= 0) ?
(n / d) : (((n + 1) / d) - 1));
}
/**
* Divides two integers and returns the floor of the quotient and
* the modulus remainder. For example,
* <code>floorDivide(-1,4)</code> returns <code>-1</code> with
* <code>3</code> as its remainder, while <code>-1/4</code> is
* <code>0</code> and <code>-1%4</code> is <code>-1</code>.
*
* @param n the numerator
* @param d a divisor which must be {@literal > 0}
* @param r an array of at least one element in which the value
* <code>mod(n, d)</code> is returned.
* @return the floor of the quotient.
*/
public static final int floorDivide(int n, int d, int[] r) {
if (n >= 0) {
r[0] = n % d;
return n / d;
}
int q = ((n + 1) / d) - 1;
r[0] = n - (q * d);
return q;
}
/**
* Divides two integers and returns the floor of the quotient and
* the modulus remainder. For example,
* <code>floorDivide(-1,4)</code> returns <code>-1</code> with
* <code>3</code> as its remainder, while <code>-1/4</code> is
* <code>0</code> and <code>-1%4</code> is <code>-1</code>.
*
* @param n the numerator
* @param d a divisor which must be {@literal > 0}
* @param r an array of at least one element in which the value
* <code>mod(n, d)</code> is returned.
* @return the floor of the quotient.
*/
public static final int floorDivide(long n, int d, int[] r) {
if (n >= 0) {
r[0] = (int)(n % d);
return (int)(n / d);
}
int q = (int)(((n + 1) / d) - 1);
r[0] = (int)(n - (q * d));
return q;
}
public static final long mod(long x, long y) {
return (x - y * floorDivide(x, y));
}
public static final int mod(int x, int y) {
return (x - y * floorDivide(x, y));
}
public static final int amod(int x, int y) {
int z = mod(x, y);
return (z == 0) ? y : z;
}
public static final long amod(long x, long y) {
long z = mod(x, y);
return (z == 0) ? y : z;
}
/**
* Mimics sprintf(buf, "%0*d", decaimal, width).
*/
public static final StringBuilder sprintf0d(StringBuilder sb, int value, int width) {
long d = value;
if (d < 0) {
sb.append('-');
d = -d;
--width;
}
int n = 10;
for (int i = 2; i < width; i++) {
n *= 10;
}
for (int i = 1; i < width && d < n; i++) {
sb.append('0');
n /= 10;
}
sb.append(d);
return sb;
}
public static final StringBuffer sprintf0d(StringBuffer sb, int value, int width) {
long d = value;
if (d < 0) {
sb.append('-');
d = -d;
--width;
}
int n = 10;
for (int i = 2; i < width; i++) {
n *= 10;
}
for (int i = 1; i < width && d < n; i++) {
sb.append('0');
n /= 10;
}
sb.append(d);
return sb;
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.Locale;
import java.util.TimeZone;
/**
* The class <code>Era</code> represents a calendar era that defines a
* period of time in which the same year numbering is used. For
* example, Gregorian year 2004 is <I>Heisei</I> 16 in the Japanese
* calendar system. An era starts at any point of time (Gregorian) that is
* represented by <code>CalendarDate</code>.
*
* <p><code>Era</code>s that are applicable to a particular calendar
* system can be obtained by calling {@link CalendarSystem#getEras}
* one of which can be used to specify a date in
* <code>CalendarDate</code>.
*
* <p>The following era names are defined in this release.
* <pre>{@code
* Calendar system Era name Since (in Gregorian)
* -----------------------------------------------------------------------
* Japanese calendar Meiji 1868-01-01T00:00:00 local time
* Taisho 1912-07-30T00:00:00 local time
* Showa 1926-12-25T00:00:00 local time
* Heisei 1989-01-08T00:00:00 local time
* -----------------------------------------------------------------------
* }</pre>
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public final class Era {
private final String name;
private final String abbr;
private final long since;
private final CalendarDate sinceDate;
private final boolean localTime;
/**
* Constructs an <code>Era</code> instance.
*
* @param name the era name (e.g., "BeforeCommonEra" for the Julian calendar system)
* @param abbr the abbreviation of the era name (e.g., "B.C.E." for "BeforeCommonEra")
* @param since the time (millisecond offset from January 1, 1970
* (Gregorian) UTC or local time) when the era starts, inclusive.
* @param localTime <code>true</code> if <code>since</code>
* specifies a local time; <code>false</code> if
* <code>since</code> specifies UTC
*/
public Era(String name, String abbr, long since, boolean localTime) {
this.name = name;
this.abbr = abbr;
this.since = since;
this.localTime = localTime;
Gregorian gcal = CalendarSystem.getGregorianCalendar();
BaseCalendar.Date d = (BaseCalendar.Date) gcal.newCalendarDate(null);
gcal.getCalendarDate(since, d);
sinceDate = new ImmutableGregorianDate(d);
}
public String getName() {
return name;
}
public String getDisplayName(Locale locale) {
return name;
}
public String getAbbreviation() {
return abbr;
}
public String getDiaplayAbbreviation(Locale locale) {
return abbr;
}
public long getSince(TimeZone zone) {
if (zone == null || !localTime) {
return since;
}
int offset = zone.getOffset(since);
return since - offset;
}
public CalendarDate getSinceDate() {
return sinceDate;
}
public boolean isLocalTime() {
return localTime;
}
public boolean equals(Object o) {
if (!(o instanceof Era)) {
return false;
}
Era that = (Era) o;
return name.equals(that.name)
&& abbr.equals(that.abbr)
&& since == that.since
&& localTime == that.localTime;
}
private int hash = 0;
public int hashCode() {
if (hash == 0) {
hash = name.hashCode() ^ abbr.hashCode() ^ (int)since ^ (int)(since >> 32)
^ (localTime ? 1 : 0);
}
return hash;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
sb.append(getName()).append(" (");
sb.append(getAbbreviation()).append(')');
sb.append(" since ").append(getSinceDate());
if (localTime) {
sb.setLength(sb.length() - 1); // remove 'Z'
sb.append(" local time");
}
sb.append(']');
return sb.toString();
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.TimeZone;
/**
* Gregorian calendar implementation.
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public class Gregorian extends BaseCalendar {
static class Date extends BaseCalendar.Date {
protected Date() {
super();
}
protected Date(TimeZone zone) {
super(zone);
}
public int getNormalizedYear() {
return getYear();
}
public void setNormalizedYear(int normalizedYear) {
setYear(normalizedYear);
}
}
Gregorian() {
}
public String getName() {
return "gregorian";
}
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
public Date getCalendarDate(long millis, CalendarDate date) {
return (Date) super.getCalendarDate(millis, date);
}
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
public Date newCalendarDate() {
return new Date();
}
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
}

View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.Locale;
import java.util.TimeZone;
class ImmutableGregorianDate extends BaseCalendar.Date {
private final BaseCalendar.Date date;
ImmutableGregorianDate(BaseCalendar.Date date) {
if (date == null) {
throw new NullPointerException();
}
this.date = date;
}
public Era getEra() {
return date.getEra();
}
public CalendarDate setEra(Era era) {
unsupported(); return this;
}
public int getYear() {
return date.getYear();
}
public CalendarDate setYear(int year) {
unsupported(); return this;
}
public CalendarDate addYear(int n) {
unsupported(); return this;
}
public boolean isLeapYear() {
return date.isLeapYear();
}
void setLeapYear(boolean leapYear) {
unsupported();
}
public int getMonth() {
return date.getMonth();
}
public CalendarDate setMonth(int month) {
unsupported(); return this;
}
public CalendarDate addMonth(int n) {
unsupported(); return this;
}
public int getDayOfMonth() {
return date.getDayOfMonth();
}
public CalendarDate setDayOfMonth(int date) {
unsupported(); return this;
}
public CalendarDate addDayOfMonth(int n) {
unsupported(); return this;
}
public int getDayOfWeek() {
return date.getDayOfWeek();
}
public int getHours() {
return date.getHours();
}
public CalendarDate setHours(int hours) {
unsupported(); return this;
}
public CalendarDate addHours(int n) {
unsupported(); return this;
}
public int getMinutes() {
return date.getMinutes();
}
public CalendarDate setMinutes(int minutes) {
unsupported(); return this;
}
public CalendarDate addMinutes(int n) {
unsupported(); return this;
}
public int getSeconds() {
return date.getSeconds();
}
public CalendarDate setSeconds(int seconds) {
unsupported(); return this;
}
public CalendarDate addSeconds(int n) {
unsupported(); return this;
}
public int getMillis() {
return date.getMillis();
}
public CalendarDate setMillis(int millis) {
unsupported(); return this;
}
public CalendarDate addMillis(int n) {
unsupported(); return this;
}
public long getTimeOfDay() {
return date.getTimeOfDay();
}
public CalendarDate setDate(int year, int month, int dayOfMonth) {
unsupported(); return this;
}
public CalendarDate addDate(int year, int month, int dayOfMonth) {
unsupported(); return this;
}
public CalendarDate setTimeOfDay(int hours, int minutes, int seconds, int millis) {
unsupported(); return this;
}
public CalendarDate addTimeOfDay(int hours, int minutes, int seconds, int millis) {
unsupported(); return this;
}
protected void setTimeOfDay(long fraction) {
unsupported();
}
public boolean isNormalized() {
return date.isNormalized();
}
public boolean isStandardTime() {
return date.isStandardTime();
}
public void setStandardTime(boolean standardTime) {
unsupported();
}
public boolean isDaylightTime() {
return date.isDaylightTime();
}
protected void setLocale(Locale loc) {
unsupported();
}
public TimeZone getZone() {
return date.getZone();
}
public CalendarDate setZone(TimeZone zoneinfo) {
unsupported(); return this;
}
public boolean isSameDate(CalendarDate date) {
return date.isSameDate(date);
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ImmutableGregorianDate)) {
return false;
}
return date.equals(((ImmutableGregorianDate) obj).date);
}
public int hashCode() {
return date.hashCode();
}
public Object clone() {
return super.clone();
}
public String toString() {
return date.toString();
}
protected void setDayOfWeek(int dayOfWeek) {
unsupported();
}
protected void setNormalized(boolean normalized) {
unsupported();
}
public int getZoneOffset() {
return date.getZoneOffset();
}
protected void setZoneOffset(int offset) {
unsupported();
}
public int getDaylightSaving() {
return date.getDaylightSaving();
}
protected void setDaylightSaving(int daylightSaving) {
unsupported();
}
public int getNormalizedYear() {
return date.getNormalizedYear();
}
public void setNormalizedYear(int normalizedYear) {
unsupported();
}
private void unsupported() {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.TimeZone;
/**
* Julian calendar implementation.
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public class JulianCalendar extends BaseCalendar {
private static final int BCE = 0;
private static final int CE = 1;
private static final Era[] eras = {
new Era("BeforeCommonEra", "B.C.E.", Long.MIN_VALUE, false),
new Era("CommonEra", "C.E.", -62135709175808L, true)
};
private static final int JULIAN_EPOCH = -1;
private static class Date extends BaseCalendar.Date {
protected Date() {
super();
setCache(1, -1L, 365); // January 1, 1 CE (Julian)
}
protected Date(TimeZone zone) {
super(zone);
setCache(1, -1L, 365); // January 1, 1 CE (Julian)
}
public Date setEra(Era era) {
if (era == null) {
throw new NullPointerException();
}
if (era != eras[0] || era != eras[1]) {
throw new IllegalArgumentException("unknown era: " + era);
}
super.setEra(era);
return this;
}
protected void setKnownEra(Era era) {
super.setEra(era);
}
public int getNormalizedYear() {
if (getEra() == eras[BCE]) {
return 1 - getYear();
}
return getYear();
}
// Use the year numbering ..., -2, -1, 0, 1, 2, ... for
// normalized years. This differs from "Calendrical
// Calculations" in which the numbering is ..., -2, -1, 1, 2,
// ...
public void setNormalizedYear(int year) {
if (year <= 0) {
setYear(1 - year);
setKnownEra(eras[BCE]);
} else {
setYear(year);
setKnownEra(eras[CE]);
}
}
public String toString() {
String time = super.toString();
time = time.substring(time.indexOf('T'));
StringBuffer sb = new StringBuffer();
Era era = getEra();
if (era != null) {
String n = era.getAbbreviation();
if (n != null) {
sb.append(n).append(' ');
}
}
sb.append(getYear()).append('-');
CalendarUtils.sprintf0d(sb, getMonth(), 2).append('-');
CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
sb.append(time);
return sb.toString();
}
}
JulianCalendar() {
setEras(eras);
}
public String getName() {
return "julian";
}
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
public Date getCalendarDate(long millis, CalendarDate date) {
return (Date) super.getCalendarDate(millis, date);
}
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
public Date newCalendarDate() {
return new Date();
}
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
/**
* @param jyear normalized Julian year
*/
public long getFixedDate(int jyear, int month, int dayOfMonth, BaseCalendar.Date cache) {
boolean isJan1 = month == JANUARY && dayOfMonth == 1;
// Look up the one year cache
if (cache != null && cache.hit(jyear)) {
if (isJan1) {
return cache.getCachedJan1();
}
return cache.getCachedJan1() + getDayOfYear(jyear, month, dayOfMonth) - 1;
}
long y = jyear;
long days = JULIAN_EPOCH - 1 + (365 * (y - 1)) + dayOfMonth;
if (y > 0) {
// CE years
days += (y - 1) / 4;
} else {
// BCE years
days += CalendarUtils.floorDivide(y - 1, 4);
}
if (month > 0) {
days += ((367 * (long) month) - 362) / 12;
} else {
days += CalendarUtils.floorDivide((367 * (long) month) - 362, 12);
}
if (month > FEBRUARY) {
days -= CalendarUtils.isJulianLeapYear(jyear) ? 1 : 2;
}
// If it's January 1, update the cache.
if (cache != null && isJan1) {
cache.setCache(jyear, days, CalendarUtils.isJulianLeapYear(jyear) ? 366 : 365);
}
return days;
}
public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
Date jdate = (Date) date;
long fd = 4 * (fixedDate - JULIAN_EPOCH) + 1464;
int year;
if (fd >= 0) {
year = (int)(fd / 1461);
} else {
year = (int) CalendarUtils.floorDivide(fd, 1461);
}
int priorDays = (int)(fixedDate - getFixedDate(year, JANUARY, 1, jdate));
boolean isLeap = CalendarUtils.isJulianLeapYear(year);
if (fixedDate >= getFixedDate(year, MARCH, 1, jdate)) {
priorDays += isLeap ? 1 : 2;
}
int month = 12 * priorDays + 373;
if (month > 0) {
month /= 367;
} else {
month = CalendarUtils.floorDivide(month, 367);
}
int dayOfMonth = (int)(fixedDate - getFixedDate(year, month, 1, jdate)) + 1;
int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate);
assert dayOfWeek > 0 : "negative day of week " + dayOfWeek;
jdate.setNormalizedYear(year);
jdate.setMonth(month);
jdate.setDayOfMonth(dayOfMonth);
jdate.setDayOfWeek(dayOfWeek);
jdate.setLeapYear(isLeap);
jdate.setNormalized(true);
}
/**
* Returns the normalized Julian year number of the given fixed date.
*/
public int getYearFromFixedDate(long fixedDate) {
int year = (int) CalendarUtils.floorDivide(4 * (fixedDate - JULIAN_EPOCH) + 1464, 1461);
return year;
}
public int getDayOfWeek(CalendarDate date) {
// TODO: should replace this with a faster calculation, such
// as cache table lookup
long fixedDate = getFixedDate(date);
return getDayOfWeekFromFixedDate(fixedDate);
}
boolean isLeapYear(int jyear) {
return CalendarUtils.isJulianLeapYear(jyear);
}
}

View file

@ -0,0 +1,420 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.security.AccessController;
import java.util.TimeZone;
import sun.security.action.GetPropertyAction;
/**
*
* @author Masayoshi Okutsu
* @since 1.6
*/
public class LocalGregorianCalendar extends BaseCalendar {
private static final Era[] JAPANESE_ERAS = {
new Era("Meiji", "M", -3218832000000L, true),
new Era("Taisho", "T", -1812153600000L, true),
new Era("Showa", "S", -1357603200000L, true),
new Era("Heisei", "H", 600220800000L, true),
};
private static boolean isValidEra(Era newEra, Era[] eras) {
Era last = eras[eras.length - 1];
if (last.getSinceDate().getYear() >= newEra.getSinceDate().getYear()) {
return false;
}
// The new era name should be unique. Its abbr may not.
String newName = newEra.getName();
for (Era era : eras) {
if (era.getName().equals(newName)) {
return false;
}
}
return true;
}
private String name;
private Era[] eras;
public static class Date extends BaseCalendar.Date {
protected Date() {
super();
}
protected Date(TimeZone zone) {
super(zone);
}
private int gregorianYear = FIELD_UNDEFINED;
@Override
public Date setEra(Era era) {
if (getEra() != era) {
super.setEra(era);
gregorianYear = FIELD_UNDEFINED;
}
return this;
}
@Override
public Date addYear(int localYear) {
super.addYear(localYear);
gregorianYear += localYear;
return this;
}
@Override
public Date setYear(int localYear) {
if (getYear() != localYear) {
super.setYear(localYear);
gregorianYear = FIELD_UNDEFINED;
}
return this;
}
@Override
public int getNormalizedYear() {
return gregorianYear;
}
@Override
public void setNormalizedYear(int normalizedYear) {
this.gregorianYear = normalizedYear;
}
void setLocalEra(Era era) {
super.setEra(era);
}
void setLocalYear(int year) {
super.setYear(year);
}
@Override
public String toString() {
String time = super.toString();
time = time.substring(time.indexOf('T'));
StringBuffer sb = new StringBuffer();
Era era = getEra();
if (era != null) {
String abbr = era.getAbbreviation();
if (abbr != null) {
sb.append(abbr);
}
}
sb.append(getYear()).append('.');
CalendarUtils.sprintf0d(sb, getMonth(), 2).append('.');
CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
sb.append(time);
return sb.toString();
}
}
static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
// Only the Japanese calendar is supported.
if (!"japanese".equals(name)) {
return null;
}
// Append an era to the predefined eras if it's given by the property.
String prop = GetPropertyAction
.privilegedGetProperty("jdk.calendar.japanese.supplemental.era");
if (prop != null) {
Era era = parseEraEntry(prop);
if (era != null) {
if (isValidEra(era, JAPANESE_ERAS)) {
int length = JAPANESE_ERAS.length;
Era[] eras = new Era[length + 1];
System.arraycopy(JAPANESE_ERAS, 0, eras, 0, length);
eras[length] = era;
return new LocalGregorianCalendar(name, eras);
}
}
}
return new LocalGregorianCalendar(name, JAPANESE_ERAS);
}
private static Era parseEraEntry(String entry) {
String[] keyValuePairs = entry.split(",");
String eraName = null;
boolean localTime = true;
long since = 0;
String abbr = null;
for (String item : keyValuePairs) {
String[] keyvalue = item.split("=");
if (keyvalue.length != 2) {
return null;
}
String key = keyvalue[0].trim();
String value = keyvalue[1].trim();
switch (key) {
case "name":
eraName = value;
break;
case "since":
if (value.endsWith("u")) {
localTime = false;
value = value.substring(0, value.length() - 1);
}
try {
since = Long.parseLong(value);
} catch (NumberFormatException e) {
return null;
}
break;
case "abbr":
abbr = value;
break;
default:
return null;
}
}
if (eraName == null || eraName.isEmpty()
|| abbr == null || abbr.isEmpty()) {
return null;
}
return new Era(eraName, abbr, since, localTime);
}
private LocalGregorianCalendar(String name, Era[] eras) {
this.name = name;
this.eras = eras;
setEras(eras);
}
@Override
public String getName() {
return name;
}
@Override
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
@Override
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
@Override
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
@Override
public Date getCalendarDate(long millis, CalendarDate date) {
Date ldate = (Date) super.getCalendarDate(millis, date);
return adjustYear(ldate, millis, ldate.getZoneOffset());
}
private Date adjustYear(Date ldate, long millis, int zoneOffset) {
int i;
for (i = eras.length - 1; i >= 0; --i) {
Era era = eras[i];
long since = era.getSince(null);
if (era.isLocalTime()) {
since -= zoneOffset;
}
if (millis >= since) {
ldate.setLocalEra(era);
int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
ldate.setLocalYear(y);
break;
}
}
if (i < 0) {
ldate.setLocalEra(null);
ldate.setLocalYear(ldate.getNormalizedYear());
}
ldate.setNormalized(true);
return ldate;
}
@Override
public Date newCalendarDate() {
return new Date();
}
@Override
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
@Override
public boolean validate(CalendarDate date) {
Date ldate = (Date) date;
Era era = ldate.getEra();
if (era != null) {
if (!validateEra(era)) {
return false;
}
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
Date tmp = newCalendarDate(date.getZone());
tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth());
normalize(tmp);
if (tmp.getEra() != era) {
return false;
}
} else {
if (date.getYear() >= eras[0].getSinceDate().getYear()) {
return false;
}
ldate.setNormalizedYear(ldate.getYear());
}
return super.validate(ldate);
}
private boolean validateEra(Era era) {
for (Era era1 : eras) {
if (era == era1) {
return true;
}
}
return false;
}
@Override
public boolean normalize(CalendarDate date) {
if (date.isNormalized()) {
return true;
}
normalizeYear(date);
Date ldate = (Date) date;
// Normalize it as a Gregorian date and get its millisecond value
super.normalize(ldate);
boolean hasMillis = false;
long millis = 0;
int year = ldate.getNormalizedYear();
int i;
Era era = null;
for (i = eras.length - 1; i >= 0; --i) {
era = eras[i];
if (era.isLocalTime()) {
CalendarDate sinceDate = era.getSinceDate();
int sinceYear = sinceDate.getYear();
if (year > sinceYear) {
break;
}
if (year == sinceYear) {
int month = ldate.getMonth();
int sinceMonth = sinceDate.getMonth();
if (month > sinceMonth) {
break;
}
if (month == sinceMonth) {
int day = ldate.getDayOfMonth();
int sinceDay = sinceDate.getDayOfMonth();
if (day > sinceDay) {
break;
}
if (day == sinceDay) {
long timeOfDay = ldate.getTimeOfDay();
long sinceTimeOfDay = sinceDate.getTimeOfDay();
if (timeOfDay >= sinceTimeOfDay) {
break;
}
--i;
break;
}
}
}
} else {
if (!hasMillis) {
millis = super.getTime(date);
hasMillis = true;
}
long since = era.getSince(date.getZone());
if (millis >= since) {
break;
}
}
}
if (i >= 0) {
ldate.setLocalEra(era);
@SuppressWarnings("null")
int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
ldate.setLocalYear(y);
} else {
// Set Gregorian year with no era
ldate.setEra(null);
ldate.setLocalYear(year);
ldate.setNormalizedYear(year);
}
ldate.setNormalized(true);
return true;
}
@Override
void normalizeMonth(CalendarDate date) {
normalizeYear(date);
super.normalizeMonth(date);
}
void normalizeYear(CalendarDate date) {
Date ldate = (Date) date;
// Set the supposed-to-be-correct Gregorian year first
// e.g., Showa 90 becomes 2015 (1926 + 90 - 1).
Era era = ldate.getEra();
if (era == null || !validateEra(era)) {
ldate.setNormalizedYear(ldate.getYear());
} else {
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
}
}
/**
* Returns whether the specified Gregorian year is a leap year.
* @see #isLeapYear(Era, int)
*/
@Override
public boolean isLeapYear(int gregorianYear) {
return CalendarUtils.isGregorianLeapYear(gregorianYear);
}
public boolean isLeapYear(Era era, int year) {
if (era == null) {
return isLeapYear(year);
}
int gyear = era.getSinceDate().getYear() + year - 1;
return isLeapYear(gyear);
}
@Override
public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
Date ldate = (Date) date;
super.getCalendarDateFromFixedDate(ldate, fixedDate);
adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);
}
}

View file

@ -0,0 +1,729 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Date;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
/**
* <code>ZoneInfo</code> is an implementation subclass of {@link
* java.util.TimeZone TimeZone} that represents GMT offsets and
* daylight saving time transitions of a time zone.
* <p>
* The daylight saving time transitions are described in the {@link
* #transitions transitions} table consisting of a chronological
* sequence of transitions of GMT offset and/or daylight saving time
* changes. Since all transitions are represented in UTC, in theory,
* <code>ZoneInfo</code> can be used with any calendar systems except
* for the {@link #getOffset(int,int,int,int,int,int) getOffset}
* method that takes Gregorian calendar date fields.
* <p>
* This table covers transitions from 1900 until 2037 (as of version
* 1.4), Before 1900, it assumes that there was no daylight saving
* time and the <code>getOffset</code> methods always return the
* {@link #getRawOffset} value. No Local Mean Time is supported. If a
* specified date is beyond the transition table and this time zone is
* supposed to observe daylight saving time in 2037, it delegates
* operations to a {@link java.util.SimpleTimeZone SimpleTimeZone}
* object created using the daylight saving time schedule as of 2037.
* <p>
* The date items, transitions, GMT offset(s), etc. are read from a database
* file. See {@link ZoneInfoFile} for details.
* @see java.util.SimpleTimeZone
* @since 1.4
*/
public class ZoneInfo extends TimeZone {
private static final int UTC_TIME = 0;
private static final int STANDARD_TIME = 1;
private static final int WALL_TIME = 2;
private static final long OFFSET_MASK = 0x0fL;
private static final long DST_MASK = 0xf0L;
private static final int DST_NSHIFT = 4;
// this bit field is reserved for abbreviation support
private static final long ABBR_MASK = 0xf00L;
private static final int TRANSITION_NSHIFT = 12;
/**
* The raw GMT offset in milliseconds between this zone and GMT.
* Negative offsets are to the west of Greenwich. To obtain local
* <em>standard</em> time, add the offset to GMT time.
* @serial
*/
private int rawOffset;
/**
* Difference in milliseconds from the original GMT offset in case
* the raw offset value has been modified by calling {@link
* #setRawOffset}. The initial value is 0.
* @serial
*/
private int rawOffsetDiff = 0;
/**
* A CRC32 value of all pairs of transition time (in milliseconds
* in <code>long</code>) in local time and its GMT offset (in
* seconds in <code>int</code>) in the chronological order. Byte
* values of each <code>long</code> and <code>int</code> are taken
* in the big endian order (i.e., MSB to LSB).
* @serial
*/
private int checksum;
/**
* The amount of time in milliseconds saved during daylight saving
* time. If <code>useDaylight</code> is false, this value is 0.
* @serial
*/
private int dstSavings;
/**
* This array describes transitions of GMT offsets of this time
* zone, including both raw offset changes and daylight saving
* time changes.
* A long integer consists of four bit fields.
* <ul>
* <li>The most significant 52-bit field represents transition
* time in milliseconds from Gregorian January 1 1970, 00:00:00
* GMT.</li>
* <li>The next 4-bit field is reserved and must be 0.</li>
* <li>The next 4-bit field is an index value to {@link #offsets
* offsets[]} for the amount of daylight saving at the
* transition. If this value is zero, it means that no daylight
* saving, not the index value zero.</li>
* <li>The least significant 4-bit field is an index value to
* {@link #offsets offsets[]} for <em>total</em> GMT offset at the
* transition.</li>
* </ul>
* If this time zone doesn't observe daylight saving time and has
* never changed any GMT offsets in the past, this value is null.
* @serial
*/
private long[] transitions;
/**
* This array holds all unique offset values in
* milliseconds. Index values to this array are stored in the
* transitions array elements.
* @serial
*/
private int[] offsets;
/**
* SimpleTimeZone parameter values. It has to have either 8 for
* {@link java.util.SimpleTimeZone#SimpleTimeZone(int, String,
* int, int , int , int , int , int , int , int , int) the
* 11-argument SimpleTimeZone constructor} or 10 for {@link
* java.util.SimpleTimeZone#SimpleTimeZone(int, String, int, int,
* int , int , int , int , int , int , int, int, int) the
* 13-argument SimpleTimeZone constructor} parameters.
* @serial
*/
private int[] simpleTimeZoneParams;
/**
* True if the raw GMT offset value would change after the time
* zone data has been generated; false, otherwise. The default
* value is false.
* @serial
*/
private boolean willGMTOffsetChange = false;
/**
* True if the object has been modified after its instantiation.
*/
private transient boolean dirty = false;
private static final long serialVersionUID = 2653134537216586139L;
/**
* A constructor.
*/
public ZoneInfo() {
}
/**
* A Constructor for CustomID.
*/
public ZoneInfo(String ID, int rawOffset) {
this(ID, rawOffset, 0, 0, null, null, null, false);
}
/**
* Constructs a ZoneInfo instance.
*
* @param ID time zone name
* @param rawOffset GMT offset in milliseconds
* @param dstSavings daylight saving value in milliseconds or 0
* (zero) if this time zone doesn't observe Daylight Saving Time.
* @param checksum CRC32 value with all transitions table entry
* values
* @param transitions transition table
* @param offsets offset value table
* @param simpleTimeZoneParams parameter values for constructing
* SimpleTimeZone
* @param willGMTOffsetChange the value of willGMTOffsetChange
*/
ZoneInfo(String ID,
int rawOffset,
int dstSavings,
int checksum,
long[] transitions,
int[] offsets,
int[] simpleTimeZoneParams,
boolean willGMTOffsetChange) {
setID(ID);
this.rawOffset = rawOffset;
this.dstSavings = dstSavings;
this.checksum = checksum;
this.transitions = transitions;
this.offsets = offsets;
this.simpleTimeZoneParams = simpleTimeZoneParams;
this.willGMTOffsetChange = willGMTOffsetChange;
}
/**
* Returns the difference in milliseconds between local time and UTC
* of given time, taking into account both the raw offset and the
* effect of daylight savings.
*
* @param date the milliseconds in UTC
* @return the milliseconds to add to UTC to get local wall time
*/
public int getOffset(long date) {
return getOffsets(date, null, UTC_TIME);
}
public int getOffsets(long utc, int[] offsets) {
return getOffsets(utc, offsets, UTC_TIME);
}
public int getOffsetsByStandard(long standard, int[] offsets) {
return getOffsets(standard, offsets, STANDARD_TIME);
}
public int getOffsetsByWall(long wall, int[] offsets) {
return getOffsets(wall, offsets, WALL_TIME);
}
private int getOffsets(long date, int[] offsets, int type) {
// if dst is never observed, there is no transition.
if (transitions == null) {
int offset = getLastRawOffset();
if (offsets != null) {
offsets[0] = offset;
offsets[1] = 0;
}
return offset;
}
date -= rawOffsetDiff;
int index = getTransitionIndex(date, type);
// prior to the transition table, returns the raw offset.
// FIXME: should support LMT.
if (index < 0) {
int offset = getLastRawOffset();
if (offsets != null) {
offsets[0] = offset;
offsets[1] = 0;
}
return offset;
}
if (index < transitions.length) {
long val = transitions[index];
int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff;
if (offsets != null) {
int dst = (int)((val >>> DST_NSHIFT) & 0xfL);
int save = (dst == 0) ? 0 : this.offsets[dst];
offsets[0] = offset - save;
offsets[1] = save;
}
return offset;
}
// beyond the transitions, delegate to SimpleTimeZone if there
// is a rule; otherwise, return rawOffset.
SimpleTimeZone tz = getLastRule();
if (tz != null) {
int rawoffset = tz.getRawOffset();
long msec = date;
if (type != UTC_TIME) {
msec -= rawOffset;
}
int dstoffset = tz.getOffset(msec) - rawOffset;
// Check if it's in a standard-to-daylight transition.
if (dstoffset > 0 && tz.getOffset(msec - dstoffset) == rawoffset) {
dstoffset = 0;
}
if (offsets != null) {
offsets[0] = rawoffset;
offsets[1] = dstoffset;
}
return rawoffset + dstoffset;
}
int offset = getLastRawOffset();
if (offsets != null) {
offsets[0] = offset;
offsets[1] = 0;
}
return offset;
}
private int getTransitionIndex(long date, int type) {
int low = 0;
int high = transitions.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
long val = transitions[mid];
long midVal = val >> TRANSITION_NSHIFT; // sign extended
if (type != UTC_TIME) {
midVal += offsets[(int)(val & OFFSET_MASK)]; // wall time
}
if (type == STANDARD_TIME) {
int dstIndex = (int)((val >>> DST_NSHIFT) & 0xfL);
if (dstIndex != 0) {
midVal -= offsets[dstIndex]; // make it standard time
}
}
if (midVal < date) {
low = mid + 1;
} else if (midVal > date) {
high = mid - 1;
} else {
return mid;
}
}
// if beyond the transitions, returns that index.
if (low >= transitions.length) {
return low;
}
return low - 1;
}
/**
* Returns the difference in milliseconds between local time and
* UTC, taking into account both the raw offset and the effect of
* daylight savings, for the specified date and time. This method
* assumes that the start and end month are distinct. This method
* assumes a Gregorian calendar for calculations.
* <p>
* <em>Note: In general, clients should use
* {@link Calendar#ZONE_OFFSET Calendar.get(ZONE_OFFSET)} +
* {@link Calendar#DST_OFFSET Calendar.get(DST_OFFSET)}
* instead of calling this method.</em>
*
* @param era The era of the given date. The value must be either
* GregorianCalendar.AD or GregorianCalendar.BC.
* @param year The year in the given date.
* @param month The month in the given date. Month is 0-based. e.g.,
* 0 for January.
* @param day The day-in-month of the given date.
* @param dayOfWeek The day-of-week of the given date.
* @param milliseconds The milliseconds in day in <em>standard</em> local time.
* @return The milliseconds to add to UTC to get local time.
*/
public int getOffset(int era, int year, int month, int day,
int dayOfWeek, int milliseconds) {
if (milliseconds < 0 || milliseconds >= AbstractCalendar.DAY_IN_MILLIS) {
throw new IllegalArgumentException();
}
if (era == java.util.GregorianCalendar.BC) { // BC
year = 1 - year;
} else if (era != java.util.GregorianCalendar.AD) {
throw new IllegalArgumentException();
}
Gregorian gcal = CalendarSystem.getGregorianCalendar();
CalendarDate date = gcal.newCalendarDate(null);
date.setDate(year, month + 1, day);
if (gcal.validate(date) == false) {
throw new IllegalArgumentException();
}
// bug-for-bug compatible argument checking
if (dayOfWeek < java.util.GregorianCalendar.SUNDAY
|| dayOfWeek > java.util.GregorianCalendar.SATURDAY) {
throw new IllegalArgumentException();
}
if (transitions == null) {
return getLastRawOffset();
}
long dateInMillis = gcal.getTime(date) + milliseconds;
dateInMillis -= (long) rawOffset; // make it UTC
return getOffsets(dateInMillis, null, UTC_TIME);
}
/**
* Sets the base time zone offset from GMT. This operation
* modifies all the transitions of this ZoneInfo object, including
* historical ones, if applicable.
*
* @param offsetMillis the base time zone offset to GMT.
* @see getRawOffset
*/
public synchronized void setRawOffset(int offsetMillis) {
if (offsetMillis == rawOffset + rawOffsetDiff) {
return;
}
rawOffsetDiff = offsetMillis - rawOffset;
if (lastRule != null) {
lastRule.setRawOffset(offsetMillis);
}
dirty = true;
}
/**
* Returns the GMT offset of the current date. This GMT offset
* value is not modified during Daylight Saving Time.
*
* @return the GMT offset value in milliseconds to add to UTC time
* to get local standard time
*/
public int getRawOffset() {
if (!willGMTOffsetChange) {
return rawOffset + rawOffsetDiff;
}
int[] offsets = new int[2];
getOffsets(System.currentTimeMillis(), offsets, UTC_TIME);
return offsets[0];
}
public boolean isDirty() {
return dirty;
}
private int getLastRawOffset() {
return rawOffset + rawOffsetDiff;
}
/**
* Queries if this time zone uses Daylight Saving Time in the last known rule.
*/
public boolean useDaylightTime() {
return (simpleTimeZoneParams != null);
}
@Override
public boolean observesDaylightTime() {
if (simpleTimeZoneParams != null) {
return true;
}
if (transitions == null) {
return false;
}
// Look up the transition table to see if it's in DST right
// now or if there's any standard-to-daylight transition at
// any future.
long utc = System.currentTimeMillis() - rawOffsetDiff;
int index = getTransitionIndex(utc, UTC_TIME);
// before transitions in the transition table
if (index < 0) {
return false;
}
// the time is in the table range.
for (int i = index; i < transitions.length; i++) {
if ((transitions[i] & DST_MASK) != 0) {
return true;
}
}
// No further DST is observed.
return false;
}
/**
* Queries if the specified date is in Daylight Saving Time.
*/
public boolean inDaylightTime(Date date) {
if (date == null) {
throw new NullPointerException();
}
if (transitions == null) {
return false;
}
long utc = date.getTime() - rawOffsetDiff;
int index = getTransitionIndex(utc, UTC_TIME);
// before transitions in the transition table
if (index < 0) {
return false;
}
// the time is in the table range.
if (index < transitions.length) {
return (transitions[index] & DST_MASK) != 0;
}
// beyond the transition table
SimpleTimeZone tz = getLastRule();
if (tz != null) {
return tz.inDaylightTime(date);
}
return false;
}
/**
* Returns the amount of time in milliseconds that the clock is advanced
* during daylight saving time is in effect in its last daylight saving time rule.
*
* @return the number of milliseconds the time is advanced with respect to
* standard time when daylight saving time is in effect.
*/
public int getDSTSavings() {
return dstSavings;
}
// /**
// * @return the last year in the transition table or -1 if this
// * time zone doesn't observe any daylight saving time.
// */
// public int getMaxTransitionYear() {
// if (transitions == null) {
// return -1;
// }
// long val = transitions[transitions.length - 1];
// int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff;
// val = (val >> TRANSITION_NSHIFT) + offset;
// CalendarDate lastDate = Gregorian.getCalendarDate(val);
// return lastDate.getYear();
// }
/**
* Returns a string representation of this time zone.
* @return the string
*/
public String toString() {
return getClass().getName() +
"[id=\"" + getID() + "\"" +
",offset=" + getLastRawOffset() +
",dstSavings=" + dstSavings +
",useDaylight=" + useDaylightTime() +
",transitions=" + ((transitions != null) ? transitions.length : 0) +
",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) +
"]";
}
/**
* Gets all available IDs supported in the Java run-time.
*
* @return an array of time zone IDs.
*/
public static String[] getAvailableIDs() {
return ZoneInfoFile.getZoneIds();
}
/**
* Gets all available IDs that have the same value as the
* specified raw GMT offset.
*
* @param rawOffset the GMT offset in milliseconds. This
* value should not include any daylight saving time.
*
* @return an array of time zone IDs.
*/
public static String[] getAvailableIDs(int rawOffset) {
return ZoneInfoFile.getZoneIds(rawOffset);
}
/**
* Gets the ZoneInfo for the given ID.
*
* @param ID the ID for a ZoneInfo. See TimeZone for detail.
*
* @return the specified ZoneInfo object, or null if there is no
* time zone of the ID.
*/
public static TimeZone getTimeZone(String ID) {
return ZoneInfoFile.getZoneInfo(ID);
}
private transient SimpleTimeZone lastRule;
/**
* Returns a SimpleTimeZone object representing the last GMT
* offset and DST schedule or null if this time zone doesn't
* observe DST.
*/
private synchronized SimpleTimeZone getLastRule() {
if (lastRule == null) {
lastRule = getLastRuleInstance();
}
return lastRule;
}
/**
* Returns a SimpleTimeZone object that represents the last
* known daylight saving time rules.
*
* @return a SimpleTimeZone object or null if this time zone
* doesn't observe DST.
*/
public SimpleTimeZone getLastRuleInstance() {
if (simpleTimeZoneParams == null) {
return null;
}
if (simpleTimeZoneParams.length == 10) {
return new SimpleTimeZone(getLastRawOffset(), getID(),
simpleTimeZoneParams[0],
simpleTimeZoneParams[1],
simpleTimeZoneParams[2],
simpleTimeZoneParams[3],
simpleTimeZoneParams[4],
simpleTimeZoneParams[5],
simpleTimeZoneParams[6],
simpleTimeZoneParams[7],
simpleTimeZoneParams[8],
simpleTimeZoneParams[9],
dstSavings);
}
return new SimpleTimeZone(getLastRawOffset(), getID(),
simpleTimeZoneParams[0],
simpleTimeZoneParams[1],
simpleTimeZoneParams[2],
simpleTimeZoneParams[3],
simpleTimeZoneParams[4],
simpleTimeZoneParams[5],
simpleTimeZoneParams[6],
simpleTimeZoneParams[7],
dstSavings);
}
/**
* Returns a copy of this <code>ZoneInfo</code>.
*/
public Object clone() {
ZoneInfo zi = (ZoneInfo) super.clone();
zi.lastRule = null;
return zi;
}
/**
* Returns a hash code value calculated from the GMT offset and
* transitions.
* @return a hash code of this time zone
*/
public int hashCode() {
return getLastRawOffset() ^ checksum;
}
/**
* Compares the equity of two ZoneInfo objects.
*
* @param obj the object to be compared with
* @return true if given object is same as this ZoneInfo object,
* false otherwise.
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ZoneInfo)) {
return false;
}
ZoneInfo that = (ZoneInfo) obj;
return (getID().equals(that.getID())
&& (getLastRawOffset() == that.getLastRawOffset())
&& (checksum == that.checksum));
}
/**
* Returns true if this zone has the same raw GMT offset value and
* transition table as another zone info. If the specified
* TimeZone object is not a ZoneInfo instance, this method returns
* true if the specified TimeZone object has the same raw GMT
* offset value with no daylight saving time.
*
* @param other the ZoneInfo object to be compared with
* @return true if the given <code>TimeZone</code> has the same
* GMT offset and transition information; false, otherwise.
*/
public boolean hasSameRules(TimeZone other) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
if (!(other instanceof ZoneInfo)) {
if (getRawOffset() != other.getRawOffset()) {
return false;
}
// if both have the same raw offset and neither observes
// DST, they have the same rule.
if ((transitions == null)
&& (useDaylightTime() == false)
&& (other.useDaylightTime() == false)) {
return true;
}
return false;
}
if (getLastRawOffset() != ((ZoneInfo)other).getLastRawOffset()) {
return false;
}
return (checksum == ((ZoneInfo)other).checksum);
}
/**
* Returns a Map from alias time zone IDs to their standard
* time zone IDs.
*
* @return the Map that holds the mappings from alias time zone IDs
* to their standard time zone IDs, or null if
* <code>ZoneInfoMappings</code> file is not available.
*/
public static Map<String, String> getAliasTable() {
return ZoneInfoFile.getAliasMap();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
// We don't know how this object from 1.4.x or earlier has
// been mutated. So it should always be marked as `dirty'.
dirty = true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,220 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.cldr;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import sun.util.locale.provider.JRELocaleProviderAdapter;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleDataMetaInfo;
/**
* LocaleProviderAdapter implementation for the CLDR locale data.
*
* @author Masayoshi Okutsu
* @author Naoto Sato
*/
public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
private static final CLDRBaseLocaleDataMetaInfo baseMetaInfo = new CLDRBaseLocaleDataMetaInfo();
// Assumption: CLDR has only one non-Base module.
private final LocaleDataMetaInfo nonBaseMetaInfo;
// parent locales map
private static volatile Map<Locale, Locale> parentLocalesMap;
static {
parentLocalesMap = new ConcurrentHashMap<>();
// Assuming these locales do NOT have irregular parent locales.
parentLocalesMap.put(Locale.ROOT, Locale.ROOT);
parentLocalesMap.put(Locale.ENGLISH, Locale.ENGLISH);
parentLocalesMap.put(Locale.US, Locale.US);
}
public CLDRLocaleProviderAdapter() {
LocaleDataMetaInfo nbmi = null;
try {
nbmi = AccessController.doPrivileged(new PrivilegedExceptionAction<LocaleDataMetaInfo>() {
@Override
public LocaleDataMetaInfo run() {
for (LocaleDataMetaInfo ldmi : ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
if (ldmi.getType() == LocaleProviderAdapter.Type.CLDR) {
return ldmi;
}
}
return null;
}
});
} catch (Exception e) {
// Catch any exception, and continue as if only CLDR's base locales exist.
}
nonBaseMetaInfo = nbmi;
}
/**
* Returns the type of this LocaleProviderAdapter
* @return the type of this
*/
@Override
public LocaleProviderAdapter.Type getAdapterType() {
return LocaleProviderAdapter.Type.CLDR;
}
@Override
public BreakIteratorProvider getBreakIteratorProvider() {
return null;
}
@Override
public CollatorProvider getCollatorProvider() {
return null;
}
@Override
public Locale[] getAvailableLocales() {
Set<String> all = createLanguageTagSet("AvailableLocales");
Locale[] locs = new Locale[all.size()];
int index = 0;
for (String tag : all) {
locs[index++] = Locale.forLanguageTag(tag);
}
return locs;
}
@Override
protected Set<String> createLanguageTagSet(String category) {
// Directly call Base tags, as we know it's in the base module.
String supportedLocaleString = baseMetaInfo.availableLanguageTags(category);
String nonBaseTags = null;
if (nonBaseMetaInfo != null) {
nonBaseTags = nonBaseMetaInfo.availableLanguageTags(category);
}
if (nonBaseTags != null) {
if (supportedLocaleString != null) {
supportedLocaleString += " " + nonBaseTags;
} else {
supportedLocaleString = nonBaseTags;
}
}
if (supportedLocaleString == null) {
return Collections.emptySet();
}
Set<String> tagset = new HashSet<>();
StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
while (tokens.hasMoreTokens()) {
tagset.add(tokens.nextToken());
}
return tagset;
}
// Implementation of ResourceBundleBasedAdapter
@Override
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
List<Locale> candidates = super.getCandidateLocales(baseName, locale);
return applyParentLocales(baseName, candidates);
}
private List<Locale> applyParentLocales(String baseName, List<Locale> candidates) {
// check irregular parents
for (int i = 0; i < candidates.size(); i++) {
Locale l = candidates.get(i);
if (!l.equals(Locale.ROOT)) {
Locale p = getParentLocale(l);
if (p != null &&
!candidates.get(i+1).equals(p)) {
List<Locale> applied = candidates.subList(0, i+1);
applied.addAll(applyParentLocales(baseName, super.getCandidateLocales(baseName, p)));
return applied;
}
}
}
return candidates;
}
private static Locale getParentLocale(Locale locale) {
Locale parent = parentLocalesMap.get(locale);
if (parent == null) {
String tag = locale.toLanguageTag();
for (Map.Entry<Locale, String[]> entry : baseMetaInfo.parentLocales().entrySet()) {
if (Arrays.binarySearch(entry.getValue(), tag) >= 0) {
parent = entry.getKey();
break;
}
}
if (parent == null) {
parent = locale; // non existent marker
}
parentLocalesMap.putIfAbsent(locale, parent);
}
if (locale.equals(parent)) {
// means no irregular parent.
parent = null;
}
return parent;
}
/**
* This method returns equivalent CLDR supported locale for zh-HK,
* no, no-NO locales so that COMPAT locales do not precede
* those locales during ResourceBundle search path.
*/
private static Locale getEquivalentLoc(Locale locale) {
switch (locale.toString()) {
case "zh_HK":
return Locale.forLanguageTag("zh-Hant-HK");
case "no":
case "no_NO":
return Locale.forLanguageTag("nb");
}
return locale;
}
@Override
public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) {
return Locale.ROOT.equals(locale)
|| langtags.contains(locale.stripExtensions().toLanguageTag())
|| langtags.contains(getEquivalentLoc(locale).toLanguageTag());
}
}

View file

@ -0,0 +1,305 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.lang.ref.SoftReference;
import java.util.StringJoiner;
public final class BaseLocale {
public static final String SEP = "_";
private static final Cache CACHE = new Cache();
private final String language;
private final String script;
private final String region;
private final String variant;
private volatile int hash;
// This method must be called only when creating the Locale.* constants.
private BaseLocale(String language, String region) {
this.language = language;
this.script = "";
this.region = region;
this.variant = "";
}
private BaseLocale(String language, String script, String region, String variant) {
this.language = (language != null) ? LocaleUtils.toLowerString(language).intern() : "";
this.script = (script != null) ? LocaleUtils.toTitleString(script).intern() : "";
this.region = (region != null) ? LocaleUtils.toUpperString(region).intern() : "";
this.variant = (variant != null) ? variant.intern() : "";
}
// Called for creating the Locale.* constants. No argument
// validation is performed.
public static BaseLocale createInstance(String language, String region) {
BaseLocale base = new BaseLocale(language, region);
CACHE.put(new Key(language, region), base);
return base;
}
public static BaseLocale getInstance(String language, String script,
String region, String variant) {
// JDK uses deprecated ISO639.1 language codes for he, yi and id
if (language != null) {
if (LocaleUtils.caseIgnoreMatch(language, "he")) {
language = "iw";
} else if (LocaleUtils.caseIgnoreMatch(language, "yi")) {
language = "ji";
} else if (LocaleUtils.caseIgnoreMatch(language, "id")) {
language = "in";
}
}
Key key = new Key(language, script, region, variant);
BaseLocale baseLocale = CACHE.get(key);
return baseLocale;
}
public String getLanguage() {
return language;
}
public String getScript() {
return script;
}
public String getRegion() {
return region;
}
public String getVariant() {
return variant;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof BaseLocale)) {
return false;
}
BaseLocale other = (BaseLocale)obj;
return language == other.language
&& script == other.script
&& region == other.region
&& variant == other.variant;
}
@Override
public String toString() {
StringJoiner sj = new StringJoiner(", ");
if (language.length() > 0) {
sj.add("language=" + language);
}
if (script.length() > 0) {
sj.add("script=" + script);
}
if (region.length() > 0) {
sj.add("region=" + region);
}
if (variant.length() > 0) {
sj.add("variant=" + variant);
}
return sj.toString();
}
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
// Generating a hash value from language, script, region and variant
h = language.hashCode();
h = 31 * h + script.hashCode();
h = 31 * h + region.hashCode();
h = 31 * h + variant.hashCode();
if (h != 0) {
hash = h;
}
}
return h;
}
private static final class Key {
private final SoftReference<String> lang;
private final SoftReference<String> scrt;
private final SoftReference<String> regn;
private final SoftReference<String> vart;
private final boolean normalized;
private final int hash;
/**
* Creates a Key. language and region must be normalized
* (intern'ed in the proper case).
*/
private Key(String language, String region) {
assert language.intern() == language
&& region.intern() == region;
lang = new SoftReference<>(language);
scrt = new SoftReference<>("");
regn = new SoftReference<>(region);
vart = new SoftReference<>("");
this.normalized = true;
int h = language.hashCode();
if (region != "") {
int len = region.length();
for (int i = 0; i < len; i++) {
h = 31 * h + LocaleUtils.toLower(region.charAt(i));
}
}
hash = h;
}
public Key(String language, String script, String region, String variant) {
this(language, script, region, variant, false);
}
private Key(String language, String script, String region,
String variant, boolean normalized) {
int h = 0;
if (language != null) {
lang = new SoftReference<>(language);
int len = language.length();
for (int i = 0; i < len; i++) {
h = 31*h + LocaleUtils.toLower(language.charAt(i));
}
} else {
lang = new SoftReference<>("");
}
if (script != null) {
scrt = new SoftReference<>(script);
int len = script.length();
for (int i = 0; i < len; i++) {
h = 31*h + LocaleUtils.toLower(script.charAt(i));
}
} else {
scrt = new SoftReference<>("");
}
if (region != null) {
regn = new SoftReference<>(region);
int len = region.length();
for (int i = 0; i < len; i++) {
h = 31*h + LocaleUtils.toLower(region.charAt(i));
}
} else {
regn = new SoftReference<>("");
}
if (variant != null) {
vart = new SoftReference<>(variant);
int len = variant.length();
for (int i = 0; i < len; i++) {
h = 31*h + variant.charAt(i);
}
} else {
vart = new SoftReference<>("");
}
hash = h;
this.normalized = normalized;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Key && this.hash == ((Key)obj).hash) {
String tl = this.lang.get();
String ol = ((Key)obj).lang.get();
if (tl != null && ol != null &&
LocaleUtils.caseIgnoreMatch(ol, tl)) {
String ts = this.scrt.get();
String os = ((Key)obj).scrt.get();
if (ts != null && os != null &&
LocaleUtils.caseIgnoreMatch(os, ts)) {
String tr = this.regn.get();
String or = ((Key)obj).regn.get();
if (tr != null && or != null &&
LocaleUtils.caseIgnoreMatch(or, tr)) {
String tv = this.vart.get();
String ov = ((Key)obj).vart.get();
return (ov != null && ov.equals(tv));
}
}
}
}
return false;
}
@Override
public int hashCode() {
return hash;
}
public static Key normalize(Key key) {
if (key.normalized) {
return key;
}
String lang = LocaleUtils.toLowerString(key.lang.get()).intern();
String scrt = LocaleUtils.toTitleString(key.scrt.get()).intern();
String regn = LocaleUtils.toUpperString(key.regn.get()).intern();
String vart = key.vart.get().intern(); // preserve upper/lower cases
return new Key(lang, scrt, regn, vart, true);
}
}
private static class Cache extends LocaleObjectCache<Key, BaseLocale> {
public Cache() {
}
@Override
protected Key normalizeKey(Key key) {
assert key.lang.get() != null &&
key.scrt.get() != null &&
key.regn.get() != null &&
key.vart.get() != null;
return Key.normalize(key);
}
@Override
protected BaseLocale createObject(Key key) {
return new BaseLocale(key.lang.get(), key.scrt.get(),
key.regn.get(), key.vart.get());
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
class Extension {
private final char key;
private String value, id;
protected Extension(char key) {
this.key = key;
}
Extension(char key, String value) {
this.key = key;
setValue(value);
}
protected void setValue(String value) {
this.value = value;
this.id = key + LanguageTag.SEP + value;
}
public char getKey() {
return key;
}
public String getValue() {
return value;
}
public String getID() {
return id;
}
public String toString() {
return getID();
}
}

View file

@ -0,0 +1,731 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class InternalLocaleBuilder {
private static final CaseInsensitiveChar PRIVATEUSE_KEY
= new CaseInsensitiveChar(LanguageTag.PRIVATEUSE);
private String language = "";
private String script = "";
private String region = "";
private String variant = "";
private Map<CaseInsensitiveChar, String> extensions;
private Set<CaseInsensitiveString> uattributes;
private Map<CaseInsensitiveString, String> ukeywords;
public InternalLocaleBuilder() {
}
public InternalLocaleBuilder setLanguage(String language) throws LocaleSyntaxException {
if (LocaleUtils.isEmpty(language)) {
this.language = "";
} else {
if (!LanguageTag.isLanguage(language)) {
throw new LocaleSyntaxException("Ill-formed language: " + language, 0);
}
this.language = language;
}
return this;
}
public InternalLocaleBuilder setScript(String script) throws LocaleSyntaxException {
if (LocaleUtils.isEmpty(script)) {
this.script = "";
} else {
if (!LanguageTag.isScript(script)) {
throw new LocaleSyntaxException("Ill-formed script: " + script, 0);
}
this.script = script;
}
return this;
}
public InternalLocaleBuilder setRegion(String region) throws LocaleSyntaxException {
if (LocaleUtils.isEmpty(region)) {
this.region = "";
} else {
if (!LanguageTag.isRegion(region)) {
throw new LocaleSyntaxException("Ill-formed region: " + region, 0);
}
this.region = region;
}
return this;
}
public InternalLocaleBuilder setVariant(String variant) throws LocaleSyntaxException {
if (LocaleUtils.isEmpty(variant)) {
this.variant = "";
} else {
// normalize separators to "_"
String var = variant.replaceAll(LanguageTag.SEP, BaseLocale.SEP);
int errIdx = checkVariants(var, BaseLocale.SEP);
if (errIdx != -1) {
throw new LocaleSyntaxException("Ill-formed variant: " + variant, errIdx);
}
this.variant = var;
}
return this;
}
public InternalLocaleBuilder addUnicodeLocaleAttribute(String attribute) throws LocaleSyntaxException {
if (!UnicodeLocaleExtension.isAttribute(attribute)) {
throw new LocaleSyntaxException("Ill-formed Unicode locale attribute: " + attribute);
}
// Use case insensitive string to prevent duplication
if (uattributes == null) {
uattributes = new HashSet<>(4);
}
uattributes.add(new CaseInsensitiveString(attribute));
return this;
}
public InternalLocaleBuilder removeUnicodeLocaleAttribute(String attribute) throws LocaleSyntaxException {
if (attribute == null || !UnicodeLocaleExtension.isAttribute(attribute)) {
throw new LocaleSyntaxException("Ill-formed Unicode locale attribute: " + attribute);
}
if (uattributes != null) {
uattributes.remove(new CaseInsensitiveString(attribute));
}
return this;
}
public InternalLocaleBuilder setUnicodeLocaleKeyword(String key, String type) throws LocaleSyntaxException {
if (!UnicodeLocaleExtension.isKey(key)) {
throw new LocaleSyntaxException("Ill-formed Unicode locale keyword key: " + key);
}
CaseInsensitiveString cikey = new CaseInsensitiveString(key);
if (type == null) {
if (ukeywords != null) {
// null type is used for remove the key
ukeywords.remove(cikey);
}
} else {
if (type.length() != 0) {
// normalize separator to "-"
String tp = type.replaceAll(BaseLocale.SEP, LanguageTag.SEP);
// validate
StringTokenIterator itr = new StringTokenIterator(tp, LanguageTag.SEP);
while (!itr.isDone()) {
String s = itr.current();
if (!UnicodeLocaleExtension.isTypeSubtag(s)) {
throw new LocaleSyntaxException("Ill-formed Unicode locale keyword type: "
+ type,
itr.currentStart());
}
itr.next();
}
}
if (ukeywords == null) {
ukeywords = new HashMap<>(4);
}
ukeywords.put(cikey, type);
}
return this;
}
public InternalLocaleBuilder setExtension(char singleton, String value) throws LocaleSyntaxException {
// validate key
boolean isBcpPrivateuse = LanguageTag.isPrivateusePrefixChar(singleton);
if (!isBcpPrivateuse && !LanguageTag.isExtensionSingletonChar(singleton)) {
throw new LocaleSyntaxException("Ill-formed extension key: " + singleton);
}
boolean remove = LocaleUtils.isEmpty(value);
CaseInsensitiveChar key = new CaseInsensitiveChar(singleton);
if (remove) {
if (UnicodeLocaleExtension.isSingletonChar(key.value())) {
// clear entire Unicode locale extension
if (uattributes != null) {
uattributes.clear();
}
if (ukeywords != null) {
ukeywords.clear();
}
} else {
if (extensions != null && extensions.containsKey(key)) {
extensions.remove(key);
}
}
} else {
// validate value
String val = value.replaceAll(BaseLocale.SEP, LanguageTag.SEP);
StringTokenIterator itr = new StringTokenIterator(val, LanguageTag.SEP);
while (!itr.isDone()) {
String s = itr.current();
boolean validSubtag;
if (isBcpPrivateuse) {
validSubtag = LanguageTag.isPrivateuseSubtag(s);
} else {
validSubtag = LanguageTag.isExtensionSubtag(s);
}
if (!validSubtag) {
throw new LocaleSyntaxException("Ill-formed extension value: " + s,
itr.currentStart());
}
itr.next();
}
if (UnicodeLocaleExtension.isSingletonChar(key.value())) {
setUnicodeLocaleExtension(val);
} else {
if (extensions == null) {
extensions = new HashMap<>(4);
}
extensions.put(key, val);
}
}
return this;
}
/*
* Set extension/private subtags in a single string representation
*/
public InternalLocaleBuilder setExtensions(String subtags) throws LocaleSyntaxException {
if (LocaleUtils.isEmpty(subtags)) {
clearExtensions();
return this;
}
subtags = subtags.replaceAll(BaseLocale.SEP, LanguageTag.SEP);
StringTokenIterator itr = new StringTokenIterator(subtags, LanguageTag.SEP);
List<String> extensions = null;
String privateuse = null;
int parsed = 0;
int start;
// Make a list of extension subtags
while (!itr.isDone()) {
String s = itr.current();
if (LanguageTag.isExtensionSingleton(s)) {
start = itr.currentStart();
String singleton = s;
StringBuilder sb = new StringBuilder(singleton);
itr.next();
while (!itr.isDone()) {
s = itr.current();
if (LanguageTag.isExtensionSubtag(s)) {
sb.append(LanguageTag.SEP).append(s);
parsed = itr.currentEnd();
} else {
break;
}
itr.next();
}
if (parsed < start) {
throw new LocaleSyntaxException("Incomplete extension '" + singleton + "'",
start);
}
if (extensions == null) {
extensions = new ArrayList<>(4);
}
extensions.add(sb.toString());
} else {
break;
}
}
if (!itr.isDone()) {
String s = itr.current();
if (LanguageTag.isPrivateusePrefix(s)) {
start = itr.currentStart();
StringBuilder sb = new StringBuilder(s);
itr.next();
while (!itr.isDone()) {
s = itr.current();
if (!LanguageTag.isPrivateuseSubtag(s)) {
break;
}
sb.append(LanguageTag.SEP).append(s);
parsed = itr.currentEnd();
itr.next();
}
if (parsed <= start) {
throw new LocaleSyntaxException("Incomplete privateuse:"
+ subtags.substring(start),
start);
} else {
privateuse = sb.toString();
}
}
}
if (!itr.isDone()) {
throw new LocaleSyntaxException("Ill-formed extension subtags:"
+ subtags.substring(itr.currentStart()),
itr.currentStart());
}
return setExtensions(extensions, privateuse);
}
/*
* Set a list of BCP47 extensions and private use subtags
* BCP47 extensions are already validated and well-formed, but may contain duplicates
*/
private InternalLocaleBuilder setExtensions(List<String> bcpExtensions, String privateuse) {
clearExtensions();
if (!LocaleUtils.isEmpty(bcpExtensions)) {
Set<CaseInsensitiveChar> done = new HashSet<>(bcpExtensions.size());
for (String bcpExt : bcpExtensions) {
CaseInsensitiveChar key = new CaseInsensitiveChar(bcpExt);
// ignore duplicates
if (!done.contains(key)) {
// each extension string contains singleton, e.g. "a-abc-def"
if (UnicodeLocaleExtension.isSingletonChar(key.value())) {
setUnicodeLocaleExtension(bcpExt.substring(2));
} else {
if (extensions == null) {
extensions = new HashMap<>(4);
}
extensions.put(key, bcpExt.substring(2));
}
}
done.add(key);
}
}
if (privateuse != null && privateuse.length() > 0) {
// privateuse string contains prefix, e.g. "x-abc-def"
if (extensions == null) {
extensions = new HashMap<>(1);
}
extensions.put(new CaseInsensitiveChar(privateuse), privateuse.substring(2));
}
return this;
}
/*
* Reset Builder's internal state with the given language tag
*/
public InternalLocaleBuilder setLanguageTag(LanguageTag langtag) {
clear();
if (!langtag.getExtlangs().isEmpty()) {
language = langtag.getExtlangs().get(0);
} else {
String lang = langtag.getLanguage();
if (!lang.equals(LanguageTag.UNDETERMINED)) {
language = lang;
}
}
script = langtag.getScript();
region = langtag.getRegion();
List<String> bcpVariants = langtag.getVariants();
if (!bcpVariants.isEmpty()) {
StringBuilder var = new StringBuilder(bcpVariants.get(0));
int size = bcpVariants.size();
for (int i = 1; i < size; i++) {
var.append(BaseLocale.SEP).append(bcpVariants.get(i));
}
variant = var.toString();
}
setExtensions(langtag.getExtensions(), langtag.getPrivateuse());
return this;
}
public InternalLocaleBuilder setLocale(BaseLocale base, LocaleExtensions localeExtensions) throws LocaleSyntaxException {
String language = base.getLanguage();
String script = base.getScript();
String region = base.getRegion();
String variant = base.getVariant();
// Special backward compatibility support
// Exception 1 - ja_JP_JP
if (language.equals("ja") && region.equals("JP") && variant.equals("JP")) {
// When locale ja_JP_JP is created, ca-japanese is always there.
// The builder ignores the variant "JP"
assert("japanese".equals(localeExtensions.getUnicodeLocaleType("ca")));
variant = "";
}
// Exception 2 - th_TH_TH
else if (language.equals("th") && region.equals("TH") && variant.equals("TH")) {
// When locale th_TH_TH is created, nu-thai is always there.
// The builder ignores the variant "TH"
assert("thai".equals(localeExtensions.getUnicodeLocaleType("nu")));
variant = "";
}
// Exception 3 - no_NO_NY
else if (language.equals("no") && region.equals("NO") && variant.equals("NY")) {
// no_NO_NY is a valid locale and used by Java 6 or older versions.
// The build ignores the variant "NY" and change the language to "nn".
language = "nn";
variant = "";
}
// Validate base locale fields before updating internal state.
// LocaleExtensions always store validated/canonicalized values,
// so no checks are necessary.
if (language.length() > 0 && !LanguageTag.isLanguage(language)) {
throw new LocaleSyntaxException("Ill-formed language: " + language);
}
if (script.length() > 0 && !LanguageTag.isScript(script)) {
throw new LocaleSyntaxException("Ill-formed script: " + script);
}
if (region.length() > 0 && !LanguageTag.isRegion(region)) {
throw new LocaleSyntaxException("Ill-formed region: " + region);
}
if (variant.length() > 0) {
int errIdx = checkVariants(variant, BaseLocale.SEP);
if (errIdx != -1) {
throw new LocaleSyntaxException("Ill-formed variant: " + variant, errIdx);
}
}
// The input locale is validated at this point.
// Now, updating builder's internal fields.
this.language = language;
this.script = script;
this.region = region;
this.variant = variant;
clearExtensions();
Set<Character> extKeys = (localeExtensions == null) ? null : localeExtensions.getKeys();
if (extKeys != null) {
// map localeExtensions back to builder's internal format
for (Character key : extKeys) {
Extension e = localeExtensions.getExtension(key);
if (e instanceof UnicodeLocaleExtension) {
UnicodeLocaleExtension ue = (UnicodeLocaleExtension)e;
for (String uatr : ue.getUnicodeLocaleAttributes()) {
if (uattributes == null) {
uattributes = new HashSet<>(4);
}
uattributes.add(new CaseInsensitiveString(uatr));
}
for (String ukey : ue.getUnicodeLocaleKeys()) {
if (ukeywords == null) {
ukeywords = new HashMap<>(4);
}
ukeywords.put(new CaseInsensitiveString(ukey), ue.getUnicodeLocaleType(ukey));
}
} else {
if (extensions == null) {
extensions = new HashMap<>(4);
}
extensions.put(new CaseInsensitiveChar(key), e.getValue());
}
}
}
return this;
}
public InternalLocaleBuilder clear() {
language = "";
script = "";
region = "";
variant = "";
clearExtensions();
return this;
}
public InternalLocaleBuilder clearExtensions() {
if (extensions != null) {
extensions.clear();
}
if (uattributes != null) {
uattributes.clear();
}
if (ukeywords != null) {
ukeywords.clear();
}
return this;
}
public BaseLocale getBaseLocale() {
String language = this.language;
String script = this.script;
String region = this.region;
String variant = this.variant;
// Special private use subtag sequence identified by "lvariant" will be
// interpreted as Java variant.
if (extensions != null) {
String privuse = extensions.get(PRIVATEUSE_KEY);
if (privuse != null) {
StringTokenIterator itr = new StringTokenIterator(privuse, LanguageTag.SEP);
boolean sawPrefix = false;
int privVarStart = -1;
while (!itr.isDone()) {
if (sawPrefix) {
privVarStart = itr.currentStart();
break;
}
if (LocaleUtils.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) {
sawPrefix = true;
}
itr.next();
}
if (privVarStart != -1) {
StringBuilder sb = new StringBuilder(variant);
if (sb.length() != 0) {
sb.append(BaseLocale.SEP);
}
sb.append(privuse.substring(privVarStart).replaceAll(LanguageTag.SEP,
BaseLocale.SEP));
variant = sb.toString();
}
}
}
return BaseLocale.getInstance(language, script, region, variant);
}
public LocaleExtensions getLocaleExtensions() {
if (LocaleUtils.isEmpty(extensions) && LocaleUtils.isEmpty(uattributes)
&& LocaleUtils.isEmpty(ukeywords)) {
return null;
}
LocaleExtensions lext = new LocaleExtensions(extensions, uattributes, ukeywords);
return lext.isEmpty() ? null : lext;
}
/*
* Remove special private use subtag sequence identified by "lvariant"
* and return the rest. Only used by LocaleExtensions
*/
static String removePrivateuseVariant(String privuseVal) {
StringTokenIterator itr = new StringTokenIterator(privuseVal, LanguageTag.SEP);
// Note: privateuse value "abc-lvariant" is unchanged
// because no subtags after "lvariant".
int prefixStart = -1;
boolean sawPrivuseVar = false;
while (!itr.isDone()) {
if (prefixStart != -1) {
// Note: privateuse value "abc-lvariant" is unchanged
// because no subtags after "lvariant".
sawPrivuseVar = true;
break;
}
if (LocaleUtils.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) {
prefixStart = itr.currentStart();
}
itr.next();
}
if (!sawPrivuseVar) {
return privuseVal;
}
assert(prefixStart == 0 || prefixStart > 1);
return (prefixStart == 0) ? null : privuseVal.substring(0, prefixStart -1);
}
/*
* Check if the given variant subtags separated by the given
* separator(s) are valid
*/
private int checkVariants(String variants, String sep) {
StringTokenIterator itr = new StringTokenIterator(variants, sep);
while (!itr.isDone()) {
String s = itr.current();
if (!LanguageTag.isVariant(s)) {
return itr.currentStart();
}
itr.next();
}
return -1;
}
/*
* Private methods parsing Unicode Locale Extension subtags.
* Duplicated attributes/keywords will be ignored.
* The input must be a valid extension subtags (excluding singleton).
*/
private void setUnicodeLocaleExtension(String subtags) {
// wipe out existing attributes/keywords
if (uattributes != null) {
uattributes.clear();
}
if (ukeywords != null) {
ukeywords.clear();
}
StringTokenIterator itr = new StringTokenIterator(subtags, LanguageTag.SEP);
// parse attributes
while (!itr.isDone()) {
if (!UnicodeLocaleExtension.isAttribute(itr.current())) {
break;
}
if (uattributes == null) {
uattributes = new HashSet<>(4);
}
uattributes.add(new CaseInsensitiveString(itr.current()));
itr.next();
}
// parse keywords
CaseInsensitiveString key = null;
String type;
int typeStart = -1;
int typeEnd = -1;
while (!itr.isDone()) {
if (key != null) {
if (UnicodeLocaleExtension.isKey(itr.current())) {
// next keyword - emit previous one
assert(typeStart == -1 || typeEnd != -1);
type = (typeStart == -1) ? "" : subtags.substring(typeStart, typeEnd);
if (ukeywords == null) {
ukeywords = new HashMap<>(4);
}
ukeywords.put(key, type);
// reset keyword info
CaseInsensitiveString tmpKey = new CaseInsensitiveString(itr.current());
key = ukeywords.containsKey(tmpKey) ? null : tmpKey;
typeStart = typeEnd = -1;
} else {
if (typeStart == -1) {
typeStart = itr.currentStart();
}
typeEnd = itr.currentEnd();
}
} else if (UnicodeLocaleExtension.isKey(itr.current())) {
// 1. first keyword or
// 2. next keyword, but previous one was duplicate
key = new CaseInsensitiveString(itr.current());
if (ukeywords != null && ukeywords.containsKey(key)) {
// duplicate
key = null;
}
}
if (!itr.hasNext()) {
if (key != null) {
// last keyword
assert(typeStart == -1 || typeEnd != -1);
type = (typeStart == -1) ? "" : subtags.substring(typeStart, typeEnd);
if (ukeywords == null) {
ukeywords = new HashMap<>(4);
}
ukeywords.put(key, type);
}
break;
}
itr.next();
}
}
static final class CaseInsensitiveString {
private final String str, lowerStr;
CaseInsensitiveString(String s) {
str = s;
lowerStr = LocaleUtils.toLowerString(s);
}
public String value() {
return str;
}
@Override
public int hashCode() {
return lowerStr.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CaseInsensitiveString)) {
return false;
}
return lowerStr.equals(((CaseInsensitiveString)obj).lowerStr);
}
}
static final class CaseInsensitiveChar {
private final char ch, lowerCh;
/**
* Constructs a CaseInsensitiveChar with the first char of the
* given s.
*/
private CaseInsensitiveChar(String s) {
this(s.charAt(0));
}
CaseInsensitiveChar(char c) {
ch = c;
lowerCh = LocaleUtils.toLower(ch);
}
public char value() {
return ch;
}
@Override
public int hashCode() {
return lowerCh;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CaseInsensitiveChar)) {
return false;
}
return lowerCh == ((CaseInsensitiveChar)obj).lowerCh;
}
}
}

View file

@ -0,0 +1,747 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
public class LanguageTag {
//
// static fields
//
public static final String SEP = "-";
public static final String PRIVATEUSE = "x";
public static final String UNDETERMINED = "und";
public static final String PRIVUSE_VARIANT_PREFIX = "lvariant";
//
// Language subtag fields
//
private String language = ""; // language subtag
private String script = ""; // script subtag
private String region = ""; // region subtag
private String privateuse = ""; // privateuse
private List<String> extlangs = Collections.emptyList(); // extlang subtags
private List<String> variants = Collections.emptyList(); // variant subtags
private List<String> extensions = Collections.emptyList(); // extensions
// Map contains grandfathered tags and its preferred mappings from
// http://www.ietf.org/rfc/rfc5646.txt
// Keys are lower-case strings.
private static final Map<String, String[]> GRANDFATHERED = new HashMap<>();
static {
// grandfathered = irregular ; non-redundant tags registered
// / regular ; during the RFC 3066 era
//
// irregular = "en-GB-oed" ; irregular tags do not match
// / "i-ami" ; the 'langtag' production and
// / "i-bnn" ; would not otherwise be
// / "i-default" ; considered 'well-formed'
// / "i-enochian" ; These tags are all valid,
// / "i-hak" ; but most are deprecated
// / "i-klingon" ; in favor of more modern
// / "i-lux" ; subtags or subtag
// / "i-mingo" ; combination
// / "i-navajo"
// / "i-pwn"
// / "i-tao"
// / "i-tay"
// / "i-tsu"
// / "sgn-BE-FR"
// / "sgn-BE-NL"
// / "sgn-CH-DE"
//
// regular = "art-lojban" ; these tags match the 'langtag'
// / "cel-gaulish" ; production, but their subtags
// / "no-bok" ; are not extended language
// / "no-nyn" ; or variant subtags: their meaning
// / "zh-guoyu" ; is defined by their registration
// / "zh-hakka" ; and all of these are deprecated
// / "zh-min" ; in favor of a more modern
// / "zh-min-nan" ; subtag or sequence of subtags
// / "zh-xiang"
final String[][] entries = {
//{"tag", "preferred"},
{"art-lojban", "jbo"},
{"cel-gaulish", "xtg-x-cel-gaulish"}, // fallback
{"en-GB-oed", "en-GB-x-oed"}, // fallback
{"i-ami", "ami"},
{"i-bnn", "bnn"},
{"i-default", "en-x-i-default"}, // fallback
{"i-enochian", "und-x-i-enochian"}, // fallback
{"i-hak", "hak"},
{"i-klingon", "tlh"},
{"i-lux", "lb"},
{"i-mingo", "see-x-i-mingo"}, // fallback
{"i-navajo", "nv"},
{"i-pwn", "pwn"},
{"i-tao", "tao"},
{"i-tay", "tay"},
{"i-tsu", "tsu"},
{"no-bok", "nb"},
{"no-nyn", "nn"},
{"sgn-BE-FR", "sfb"},
{"sgn-BE-NL", "vgt"},
{"sgn-CH-DE", "sgg"},
{"zh-guoyu", "cmn"},
{"zh-hakka", "hak"},
{"zh-min", "nan-x-zh-min"}, // fallback
{"zh-min-nan", "nan"},
{"zh-xiang", "hsn"},
};
for (String[] e : entries) {
GRANDFATHERED.put(LocaleUtils.toLowerString(e[0]), e);
}
}
private LanguageTag() {
}
/*
* BNF in RFC5646
*
* Language-Tag = langtag ; normal language tags
* / privateuse ; private use tag
* / grandfathered ; grandfathered tags
*
*
* langtag = language
* ["-" script]
* ["-" region]
* *("-" variant)
* *("-" extension)
* ["-" privateuse]
*
* language = 2*3ALPHA ; shortest ISO 639 code
* ["-" extlang] ; sometimes followed by
* ; extended language subtags
* / 4ALPHA ; or reserved for future use
* / 5*8ALPHA ; or registered language subtag
*
* extlang = 3ALPHA ; selected ISO 639 codes
* *2("-" 3ALPHA) ; permanently reserved
*
* script = 4ALPHA ; ISO 15924 code
*
* region = 2ALPHA ; ISO 3166-1 code
* / 3DIGIT ; UN M.49 code
*
* variant = 5*8alphanum ; registered variants
* / (DIGIT 3alphanum)
*
* extension = singleton 1*("-" (2*8alphanum))
*
* ; Single alphanumerics
* ; "x" reserved for private use
* singleton = DIGIT ; 0 - 9
* / %x41-57 ; A - W
* / %x59-5A ; Y - Z
* / %x61-77 ; a - w
* / %x79-7A ; y - z
*
* privateuse = "x" 1*("-" (1*8alphanum))
*
*/
public static LanguageTag parse(String languageTag, ParseStatus sts) {
if (sts == null) {
sts = new ParseStatus();
} else {
sts.reset();
}
StringTokenIterator itr;
// Check if the tag is grandfathered
String[] gfmap = GRANDFATHERED.get(LocaleUtils.toLowerString(languageTag));
if (gfmap != null) {
// use preferred mapping
itr = new StringTokenIterator(gfmap[1], SEP);
} else {
itr = new StringTokenIterator(languageTag, SEP);
}
LanguageTag tag = new LanguageTag();
// langtag must start with either language or privateuse
if (tag.parseLanguage(itr, sts)) {
tag.parseExtlangs(itr, sts);
tag.parseScript(itr, sts);
tag.parseRegion(itr, sts);
tag.parseVariants(itr, sts);
tag.parseExtensions(itr, sts);
}
tag.parsePrivateuse(itr, sts);
if (!itr.isDone() && !sts.isError()) {
String s = itr.current();
sts.errorIndex = itr.currentStart();
if (s.length() == 0) {
sts.errorMsg = "Empty subtag";
} else {
sts.errorMsg = "Invalid subtag: " + s;
}
}
return tag;
}
//
// Language subtag parsers
//
private boolean parseLanguage(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
String s = itr.current();
if (isLanguage(s)) {
found = true;
language = s;
sts.parseLength = itr.currentEnd();
itr.next();
}
return found;
}
private boolean parseExtlangs(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
while (!itr.isDone()) {
String s = itr.current();
if (!isExtlang(s)) {
break;
}
found = true;
if (extlangs.isEmpty()) {
extlangs = new ArrayList<>(3);
}
extlangs.add(s);
sts.parseLength = itr.currentEnd();
itr.next();
if (extlangs.size() == 3) {
// Maximum 3 extlangs
break;
}
}
return found;
}
private boolean parseScript(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
String s = itr.current();
if (isScript(s)) {
found = true;
script = s;
sts.parseLength = itr.currentEnd();
itr.next();
}
return found;
}
private boolean parseRegion(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
String s = itr.current();
if (isRegion(s)) {
found = true;
region = s;
sts.parseLength = itr.currentEnd();
itr.next();
}
return found;
}
private boolean parseVariants(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
while (!itr.isDone()) {
String s = itr.current();
if (!isVariant(s)) {
break;
}
found = true;
if (variants.isEmpty()) {
variants = new ArrayList<>(3);
}
variants.add(s);
sts.parseLength = itr.currentEnd();
itr.next();
}
return found;
}
private boolean parseExtensions(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
while (!itr.isDone()) {
String s = itr.current();
if (isExtensionSingleton(s)) {
int start = itr.currentStart();
String singleton = s;
StringBuilder sb = new StringBuilder(singleton);
itr.next();
while (!itr.isDone()) {
s = itr.current();
if (isExtensionSubtag(s)) {
sb.append(SEP).append(s);
sts.parseLength = itr.currentEnd();
} else {
break;
}
itr.next();
}
if (sts.parseLength <= start) {
sts.errorIndex = start;
sts.errorMsg = "Incomplete extension '" + singleton + "'";
break;
}
if (extensions.isEmpty()) {
extensions = new ArrayList<>(4);
}
extensions.add(sb.toString());
found = true;
} else {
break;
}
}
return found;
}
private boolean parsePrivateuse(StringTokenIterator itr, ParseStatus sts) {
if (itr.isDone() || sts.isError()) {
return false;
}
boolean found = false;
String s = itr.current();
if (isPrivateusePrefix(s)) {
int start = itr.currentStart();
StringBuilder sb = new StringBuilder(s);
itr.next();
while (!itr.isDone()) {
s = itr.current();
if (!isPrivateuseSubtag(s)) {
break;
}
sb.append(SEP).append(s);
sts.parseLength = itr.currentEnd();
itr.next();
}
if (sts.parseLength <= start) {
// need at least 1 private subtag
sts.errorIndex = start;
sts.errorMsg = "Incomplete privateuse";
} else {
privateuse = sb.toString();
found = true;
}
}
return found;
}
public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions localeExtensions) {
LanguageTag tag = new LanguageTag();
String language = baseLocale.getLanguage();
String script = baseLocale.getScript();
String region = baseLocale.getRegion();
String variant = baseLocale.getVariant();
boolean hasSubtag = false;
String privuseVar = null; // store ill-formed variant subtags
if (isLanguage(language)) {
// Convert a deprecated language code to its new code
if (language.equals("iw")) {
language = "he";
} else if (language.equals("ji")) {
language = "yi";
} else if (language.equals("in")) {
language = "id";
}
tag.language = language;
}
if (isScript(script)) {
tag.script = canonicalizeScript(script);
hasSubtag = true;
}
if (isRegion(region)) {
tag.region = canonicalizeRegion(region);
hasSubtag = true;
}
// Special handling for no_NO_NY - use nn_NO for language tag
if (tag.language.equals("no") && tag.region.equals("NO") && variant.equals("NY")) {
tag.language = "nn";
variant = "";
}
if (variant.length() > 0) {
List<String> variants = null;
StringTokenIterator varitr = new StringTokenIterator(variant, BaseLocale.SEP);
while (!varitr.isDone()) {
String var = varitr.current();
if (!isVariant(var)) {
break;
}
if (variants == null) {
variants = new ArrayList<>();
}
variants.add(var); // Do not canonicalize!
varitr.next();
}
if (variants != null) {
tag.variants = variants;
hasSubtag = true;
}
if (!varitr.isDone()) {
// ill-formed variant subtags
StringJoiner sj = new StringJoiner(SEP);
while (!varitr.isDone()) {
String prvv = varitr.current();
if (!isPrivateuseSubtag(prvv)) {
// cannot use private use subtag - truncated
break;
}
sj.add(prvv);
varitr.next();
}
if (sj.length() > 0) {
privuseVar = sj.toString();
}
}
}
List<String> extensions = null;
String privateuse = null;
if (localeExtensions != null) {
Set<Character> locextKeys = localeExtensions.getKeys();
for (Character locextKey : locextKeys) {
Extension ext = localeExtensions.getExtension(locextKey);
if (isPrivateusePrefixChar(locextKey)) {
privateuse = ext.getValue();
} else {
if (extensions == null) {
extensions = new ArrayList<>();
}
extensions.add(locextKey.toString() + SEP + ext.getValue());
}
}
}
if (extensions != null) {
tag.extensions = extensions;
hasSubtag = true;
}
// append ill-formed variant subtags to private use
if (privuseVar != null) {
if (privateuse == null) {
privateuse = PRIVUSE_VARIANT_PREFIX + SEP + privuseVar;
} else {
privateuse = privateuse + SEP + PRIVUSE_VARIANT_PREFIX
+ SEP + privuseVar.replace(BaseLocale.SEP, SEP);
}
}
if (privateuse != null) {
tag.privateuse = privateuse;
}
if (tag.language.length() == 0 && (hasSubtag || privateuse == null)) {
// use lang "und" when 1) no language is available AND
// 2) any of other subtags other than private use are available or
// no private use tag is available
tag.language = UNDETERMINED;
}
return tag;
}
//
// Getter methods for language subtag fields
//
public String getLanguage() {
return language;
}
public List<String> getExtlangs() {
if (extlangs.isEmpty()) {
return Collections.emptyList();
}
return Collections.unmodifiableList(extlangs);
}
public String getScript() {
return script;
}
public String getRegion() {
return region;
}
public List<String> getVariants() {
if (variants.isEmpty()) {
return Collections.emptyList();
}
return Collections.unmodifiableList(variants);
}
public List<String> getExtensions() {
if (extensions.isEmpty()) {
return Collections.emptyList();
}
return Collections.unmodifiableList(extensions);
}
public String getPrivateuse() {
return privateuse;
}
//
// Language subtag syntax checking methods
//
public static boolean isLanguage(String s) {
// language = 2*3ALPHA ; shortest ISO 639 code
// ["-" extlang] ; sometimes followed by
// ; extended language subtags
// / 4ALPHA ; or reserved for future use
// / 5*8ALPHA ; or registered language subtag
int len = s.length();
return (len >= 2) && (len <= 8) && LocaleUtils.isAlphaString(s);
}
public static boolean isExtlang(String s) {
// extlang = 3ALPHA ; selected ISO 639 codes
// *2("-" 3ALPHA) ; permanently reserved
return (s.length() == 3) && LocaleUtils.isAlphaString(s);
}
public static boolean isScript(String s) {
// script = 4ALPHA ; ISO 15924 code
return (s.length() == 4) && LocaleUtils.isAlphaString(s);
}
public static boolean isRegion(String s) {
// region = 2ALPHA ; ISO 3166-1 code
// / 3DIGIT ; UN M.49 code
return ((s.length() == 2) && LocaleUtils.isAlphaString(s))
|| ((s.length() == 3) && LocaleUtils.isNumericString(s));
}
public static boolean isVariant(String s) {
// variant = 5*8alphanum ; registered variants
// / (DIGIT 3alphanum)
int len = s.length();
if (len >= 5 && len <= 8) {
return LocaleUtils.isAlphaNumericString(s);
}
if (len == 4) {
return LocaleUtils.isNumeric(s.charAt(0))
&& LocaleUtils.isAlphaNumeric(s.charAt(1))
&& LocaleUtils.isAlphaNumeric(s.charAt(2))
&& LocaleUtils.isAlphaNumeric(s.charAt(3));
}
return false;
}
public static boolean isExtensionSingleton(String s) {
// singleton = DIGIT ; 0 - 9
// / %x41-57 ; A - W
// / %x59-5A ; Y - Z
// / %x61-77 ; a - w
// / %x79-7A ; y - z
return (s.length() == 1)
&& LocaleUtils.isAlphaString(s)
&& !LocaleUtils.caseIgnoreMatch(PRIVATEUSE, s);
}
public static boolean isExtensionSingletonChar(char c) {
return isExtensionSingleton(String.valueOf(c));
}
public static boolean isExtensionSubtag(String s) {
// extension = singleton 1*("-" (2*8alphanum))
int len = s.length();
return (len >= 2) && (len <= 8) && LocaleUtils.isAlphaNumericString(s);
}
public static boolean isPrivateusePrefix(String s) {
// privateuse = "x" 1*("-" (1*8alphanum))
return (s.length() == 1)
&& LocaleUtils.caseIgnoreMatch(PRIVATEUSE, s);
}
public static boolean isPrivateusePrefixChar(char c) {
return (LocaleUtils.caseIgnoreMatch(PRIVATEUSE, String.valueOf(c)));
}
public static boolean isPrivateuseSubtag(String s) {
// privateuse = "x" 1*("-" (1*8alphanum))
int len = s.length();
return (len >= 1) && (len <= 8) && LocaleUtils.isAlphaNumericString(s);
}
//
// Language subtag canonicalization methods
//
public static String canonicalizeLanguage(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizeExtlang(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizeScript(String s) {
return LocaleUtils.toTitleString(s);
}
public static String canonicalizeRegion(String s) {
return LocaleUtils.toUpperString(s);
}
public static String canonicalizeVariant(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizeExtension(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizeExtensionSingleton(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizeExtensionSubtag(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizePrivateuse(String s) {
return LocaleUtils.toLowerString(s);
}
public static String canonicalizePrivateuseSubtag(String s) {
return LocaleUtils.toLowerString(s);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (language.length() > 0) {
sb.append(language);
for (String extlang : extlangs) {
sb.append(SEP).append(extlang);
}
if (script.length() > 0) {
sb.append(SEP).append(script);
}
if (region.length() > 0) {
sb.append(SEP).append(region);
}
for (String variant : variants) {
sb.append(SEP).append(variant);
}
for (String extension : extensions) {
sb.append(SEP).append(extension);
}
}
if (privateuse.length() > 0) {
if (sb.length() > 0) {
sb.append(SEP);
}
sb.append(privateuse);
}
return sb.toString();
}
}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import sun.util.locale.InternalLocaleBuilder.CaseInsensitiveChar;
import sun.util.locale.InternalLocaleBuilder.CaseInsensitiveString;
public class LocaleExtensions {
private final Map<Character, Extension> extensionMap;
private final String id;
public static final LocaleExtensions CALENDAR_JAPANESE
= new LocaleExtensions("u-ca-japanese",
UnicodeLocaleExtension.SINGLETON,
UnicodeLocaleExtension.CA_JAPANESE);
public static final LocaleExtensions NUMBER_THAI
= new LocaleExtensions("u-nu-thai",
UnicodeLocaleExtension.SINGLETON,
UnicodeLocaleExtension.NU_THAI);
private LocaleExtensions(String id, Character key, Extension value) {
this.id = id;
this.extensionMap = Collections.singletonMap(key, value);
}
/*
* Package private constructor, only used by InternalLocaleBuilder.
*/
LocaleExtensions(Map<CaseInsensitiveChar, String> extensions,
Set<CaseInsensitiveString> uattributes,
Map<CaseInsensitiveString, String> ukeywords) {
boolean hasExtension = !LocaleUtils.isEmpty(extensions);
boolean hasUAttributes = !LocaleUtils.isEmpty(uattributes);
boolean hasUKeywords = !LocaleUtils.isEmpty(ukeywords);
if (!hasExtension && !hasUAttributes && !hasUKeywords) {
id = "";
extensionMap = Collections.emptyMap();
return;
}
// Build extension map
SortedMap<Character, Extension> map = new TreeMap<>();
if (hasExtension) {
for (Entry<CaseInsensitiveChar, String> ext : extensions.entrySet()) {
char key = LocaleUtils.toLower(ext.getKey().value());
String value = ext.getValue();
if (LanguageTag.isPrivateusePrefixChar(key)) {
// we need to exclude special variant in privuateuse, e.g. "x-abc-lvariant-DEF"
value = InternalLocaleBuilder.removePrivateuseVariant(value);
if (value == null) {
continue;
}
}
map.put(key, new Extension(key, LocaleUtils.toLowerString(value)));
}
}
if (hasUAttributes || hasUKeywords) {
SortedSet<String> uaset = null;
SortedMap<String, String> ukmap = null;
if (hasUAttributes) {
uaset = new TreeSet<>();
for (CaseInsensitiveString cis : uattributes) {
uaset.add(LocaleUtils.toLowerString(cis.value()));
}
}
if (hasUKeywords) {
ukmap = new TreeMap<>();
for (Entry<CaseInsensitiveString, String> kwd : ukeywords.entrySet()) {
String key = LocaleUtils.toLowerString(kwd.getKey().value());
String type = LocaleUtils.toLowerString(kwd.getValue());
ukmap.put(key, type);
}
}
UnicodeLocaleExtension ule = new UnicodeLocaleExtension(uaset, ukmap);
map.put(UnicodeLocaleExtension.SINGLETON, ule);
}
if (map.isEmpty()) {
// this could happen when only privuateuse with special variant
id = "";
extensionMap = Collections.emptyMap();
} else {
id = toID(map);
extensionMap = map;
}
}
public Set<Character> getKeys() {
if (extensionMap.isEmpty()) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(extensionMap.keySet());
}
public Extension getExtension(Character key) {
return extensionMap.get(LocaleUtils.toLower(key));
}
public String getExtensionValue(Character key) {
Extension ext = extensionMap.get(LocaleUtils.toLower(key));
if (ext == null) {
return null;
}
return ext.getValue();
}
public Set<String> getUnicodeLocaleAttributes() {
Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON);
if (ext == null) {
return Collections.emptySet();
}
assert (ext instanceof UnicodeLocaleExtension);
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleAttributes();
}
public Set<String> getUnicodeLocaleKeys() {
Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON);
if (ext == null) {
return Collections.emptySet();
}
assert (ext instanceof UnicodeLocaleExtension);
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleKeys();
}
public String getUnicodeLocaleType(String unicodeLocaleKey) {
Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON);
if (ext == null) {
return null;
}
assert (ext instanceof UnicodeLocaleExtension);
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(LocaleUtils.toLowerString(unicodeLocaleKey));
}
public boolean isEmpty() {
return extensionMap.isEmpty();
}
public static boolean isValidKey(char c) {
return LanguageTag.isExtensionSingletonChar(c) || LanguageTag.isPrivateusePrefixChar(c);
}
public static boolean isValidUnicodeLocaleKey(String ukey) {
return UnicodeLocaleExtension.isKey(ukey);
}
private static String toID(SortedMap<Character, Extension> map) {
StringBuilder buf = new StringBuilder();
Extension privuse = null;
for (Entry<Character, Extension> entry : map.entrySet()) {
char singleton = entry.getKey();
Extension extension = entry.getValue();
if (LanguageTag.isPrivateusePrefixChar(singleton)) {
privuse = extension;
} else {
if (buf.length() > 0) {
buf.append(LanguageTag.SEP);
}
buf.append(extension);
}
}
if (privuse != null) {
if (buf.length() > 0) {
buf.append(LanguageTag.SEP);
}
buf.append(privuse);
}
return buf.toString();
}
@Override
public String toString() {
return id;
}
public String getID() {
return id;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof LocaleExtensions)) {
return false;
}
return id.equals(((LocaleExtensions)other).id);
}
}

View file

@ -0,0 +1,717 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Locale.*;
import static java.util.Locale.FilteringMode.*;
import static java.util.Locale.LanguageRange.*;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* Implementation for BCP47 Locale matching
*
*/
public final class LocaleMatcher {
public static List<Locale> filter(List<LanguageRange> priorityList,
Collection<Locale> locales,
FilteringMode mode) {
if (priorityList.isEmpty() || locales.isEmpty()) {
return new ArrayList<>(); // need to return a empty mutable List
}
// Create a list of language tags to be matched.
List<String> tags = new ArrayList<>();
for (Locale locale : locales) {
tags.add(locale.toLanguageTag());
}
// Filter language tags.
List<String> filteredTags = filterTags(priorityList, tags, mode);
// Create a list of matching locales.
List<Locale> filteredLocales = new ArrayList<>(filteredTags.size());
for (String tag : filteredTags) {
filteredLocales.add(Locale.forLanguageTag(tag));
}
return filteredLocales;
}
public static List<String> filterTags(List<LanguageRange> priorityList,
Collection<String> tags,
FilteringMode mode) {
if (priorityList.isEmpty() || tags.isEmpty()) {
return new ArrayList<>(); // need to return a empty mutable List
}
ArrayList<LanguageRange> list;
if (mode == EXTENDED_FILTERING) {
return filterExtended(priorityList, tags);
} else {
list = new ArrayList<>();
for (LanguageRange lr : priorityList) {
String range = lr.getRange();
if (range.startsWith("*-")
|| range.indexOf("-*") != -1) { // Extended range
if (mode == AUTOSELECT_FILTERING) {
return filterExtended(priorityList, tags);
} else if (mode == MAP_EXTENDED_RANGES) {
if (range.charAt(0) == '*') {
range = "*";
} else {
range = range.replaceAll("-[*]", "");
}
list.add(new LanguageRange(range, lr.getWeight()));
} else if (mode == REJECT_EXTENDED_RANGES) {
throw new IllegalArgumentException("An extended range \""
+ range
+ "\" found in REJECT_EXTENDED_RANGES mode.");
}
} else { // Basic range
list.add(lr);
}
}
return filterBasic(list, tags);
}
}
private static List<String> filterBasic(List<LanguageRange> priorityList,
Collection<String> tags) {
int splitIndex = splitRanges(priorityList);
List<LanguageRange> nonZeroRanges;
List<LanguageRange> zeroRanges;
if (splitIndex != -1) {
nonZeroRanges = priorityList.subList(0, splitIndex);
zeroRanges = priorityList.subList(splitIndex, priorityList.size());
} else {
nonZeroRanges = priorityList;
zeroRanges = List.of();
}
List<String> list = new ArrayList<>();
for (LanguageRange lr : nonZeroRanges) {
String range = lr.getRange();
if (range.equals("*")) {
tags = removeTagsMatchingBasicZeroRange(zeroRanges, tags);
return new ArrayList<String>(tags);
} else {
for (String tag : tags) {
// change to lowercase for case-insensitive matching
String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
if (lowerCaseTag.startsWith(range)) {
int len = range.length();
if ((lowerCaseTag.length() == len
|| lowerCaseTag.charAt(len) == '-')
&& !caseInsensitiveMatch(list, lowerCaseTag)
&& !shouldIgnoreFilterBasicMatch(zeroRanges,
lowerCaseTag)) {
// preserving the case of the input tag
list.add(tag);
}
}
}
}
}
return list;
}
/**
* Removes the tag(s) which are falling in the basic exclusion range(s) i.e
* range(s) with q=0 and returns the updated collection. If the basic
* language ranges contains '*' as one of its non zero range then instead of
* returning all the tags, remove those which are matching the range with
* quality weight q=0.
*/
private static Collection<String> removeTagsMatchingBasicZeroRange(
List<LanguageRange> zeroRange, Collection<String> tags) {
if (zeroRange.isEmpty()) {
tags = removeDuplicates(tags);
return tags;
}
List<String> matchingTags = new ArrayList<>();
for (String tag : tags) {
// change to lowercase for case-insensitive matching
String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
if (!shouldIgnoreFilterBasicMatch(zeroRange, lowerCaseTag)
&& !caseInsensitiveMatch(matchingTags, lowerCaseTag)) {
matchingTags.add(tag); // preserving the case of the input tag
}
}
return matchingTags;
}
/**
* Remove duplicate tags from the given {@code tags} by
* ignoring case considerations.
*/
private static Collection<String> removeDuplicates(
Collection<String> tags) {
Set<String> distinctTags = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
return tags.stream().filter(x -> distinctTags.add(x))
.collect(Collectors.toList());
}
/**
* Returns true if the given {@code list} contains an element which matches
* with the given {@code tag} ignoring case considerations.
*/
private static boolean caseInsensitiveMatch(List<String> list, String tag) {
return list.stream().anyMatch((element)
-> (element.equalsIgnoreCase(tag)));
}
/**
* The tag which is falling in the basic exclusion range(s) should not
* be considered as the matching tag. Ignores the tag matching with the
* non-zero ranges, if the tag also matches with one of the basic exclusion
* ranges i.e. range(s) having quality weight q=0
*/
private static boolean shouldIgnoreFilterBasicMatch(
List<LanguageRange> zeroRange, String tag) {
if (zeroRange.isEmpty()) {
return false;
}
for (LanguageRange lr : zeroRange) {
String range = lr.getRange();
if (range.equals("*")) {
return true;
}
if (tag.startsWith(range)) {
int len = range.length();
if ((tag.length() == len || tag.charAt(len) == '-')) {
return true;
}
}
}
return false;
}
private static List<String> filterExtended(List<LanguageRange> priorityList,
Collection<String> tags) {
int splitIndex = splitRanges(priorityList);
List<LanguageRange> nonZeroRanges;
List<LanguageRange> zeroRanges;
if (splitIndex != -1) {
nonZeroRanges = priorityList.subList(0, splitIndex);
zeroRanges = priorityList.subList(splitIndex, priorityList.size());
} else {
nonZeroRanges = priorityList;
zeroRanges = List.of();
}
List<String> list = new ArrayList<>();
for (LanguageRange lr : nonZeroRanges) {
String range = lr.getRange();
if (range.equals("*")) {
tags = removeTagsMatchingExtendedZeroRange(zeroRanges, tags);
return new ArrayList<String>(tags);
}
String[] rangeSubtags = range.split("-");
for (String tag : tags) {
// change to lowercase for case-insensitive matching
String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
String[] tagSubtags = lowerCaseTag.split("-");
if (!rangeSubtags[0].equals(tagSubtags[0])
&& !rangeSubtags[0].equals("*")) {
continue;
}
int rangeIndex = matchFilterExtendedSubtags(rangeSubtags,
tagSubtags);
if (rangeSubtags.length == rangeIndex
&& !caseInsensitiveMatch(list, lowerCaseTag)
&& !shouldIgnoreFilterExtendedMatch(zeroRanges,
lowerCaseTag)) {
list.add(tag); // preserve the case of the input tag
}
}
}
return list;
}
/**
* Removes the tag(s) which are falling in the extended exclusion range(s)
* i.e range(s) with q=0 and returns the updated collection. If the extended
* language ranges contains '*' as one of its non zero range then instead of
* returning all the tags, remove those which are matching the range with
* quality weight q=0.
*/
private static Collection<String> removeTagsMatchingExtendedZeroRange(
List<LanguageRange> zeroRange, Collection<String> tags) {
if (zeroRange.isEmpty()) {
tags = removeDuplicates(tags);
return tags;
}
List<String> matchingTags = new ArrayList<>();
for (String tag : tags) {
// change to lowercase for case-insensitive matching
String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
if (!shouldIgnoreFilterExtendedMatch(zeroRange, lowerCaseTag)
&& !caseInsensitiveMatch(matchingTags, lowerCaseTag)) {
matchingTags.add(tag); // preserve the case of the input tag
}
}
return matchingTags;
}
/**
* The tag which is falling in the extended exclusion range(s) should
* not be considered as the matching tag. Ignores the tag matching with the
* non zero range(s), if the tag also matches with one of the extended
* exclusion range(s) i.e. range(s) having quality weight q=0
*/
private static boolean shouldIgnoreFilterExtendedMatch(
List<LanguageRange> zeroRange, String tag) {
if (zeroRange.isEmpty()) {
return false;
}
String[] tagSubtags = tag.split("-");
for (LanguageRange lr : zeroRange) {
String range = lr.getRange();
if (range.equals("*")) {
return true;
}
String[] rangeSubtags = range.split("-");
if (!rangeSubtags[0].equals(tagSubtags[0])
&& !rangeSubtags[0].equals("*")) {
continue;
}
int rangeIndex = matchFilterExtendedSubtags(rangeSubtags,
tagSubtags);
if (rangeSubtags.length == rangeIndex) {
return true;
}
}
return false;
}
private static int matchFilterExtendedSubtags(String[] rangeSubtags,
String[] tagSubtags) {
int rangeIndex = 1;
int tagIndex = 1;
while (rangeIndex < rangeSubtags.length
&& tagIndex < tagSubtags.length) {
if (rangeSubtags[rangeIndex].equals("*")) {
rangeIndex++;
} else if (rangeSubtags[rangeIndex]
.equals(tagSubtags[tagIndex])) {
rangeIndex++;
tagIndex++;
} else if (tagSubtags[tagIndex].length() == 1
&& !tagSubtags[tagIndex].equals("*")) {
break;
} else {
tagIndex++;
}
}
return rangeIndex;
}
public static Locale lookup(List<LanguageRange> priorityList,
Collection<Locale> locales) {
if (priorityList.isEmpty() || locales.isEmpty()) {
return null;
}
// Create a list of language tags to be matched.
List<String> tags = new ArrayList<>();
for (Locale locale : locales) {
tags.add(locale.toLanguageTag());
}
// Look up a language tags.
String lookedUpTag = lookupTag(priorityList, tags);
if (lookedUpTag == null) {
return null;
} else {
return Locale.forLanguageTag(lookedUpTag);
}
}
public static String lookupTag(List<LanguageRange> priorityList,
Collection<String> tags) {
if (priorityList.isEmpty() || tags.isEmpty()) {
return null;
}
int splitIndex = splitRanges(priorityList);
List<LanguageRange> nonZeroRanges;
List<LanguageRange> zeroRanges;
if (splitIndex != -1) {
nonZeroRanges = priorityList.subList(0, splitIndex);
zeroRanges = priorityList.subList(splitIndex, priorityList.size());
} else {
nonZeroRanges = priorityList;
zeroRanges = List.of();
}
for (LanguageRange lr : nonZeroRanges) {
String range = lr.getRange();
// Special language range ("*") is ignored in lookup.
if (range.equals("*")) {
continue;
}
String rangeForRegex = range.replace("*", "\\p{Alnum}*");
while (rangeForRegex.length() > 0) {
for (String tag : tags) {
// change to lowercase for case-insensitive matching
String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
if (lowerCaseTag.matches(rangeForRegex)
&& !shouldIgnoreLookupMatch(zeroRanges, lowerCaseTag)) {
return tag; // preserve the case of the input tag
}
}
// Truncate from the end....
rangeForRegex = truncateRange(rangeForRegex);
}
}
return null;
}
/**
* The tag which is falling in the exclusion range(s) should not be
* considered as the matching tag. Ignores the tag matching with the
* non zero range(s), if the tag also matches with one of the exclusion
* range(s) i.e. range(s) having quality weight q=0.
*/
private static boolean shouldIgnoreLookupMatch(List<LanguageRange> zeroRange,
String tag) {
for (LanguageRange lr : zeroRange) {
String range = lr.getRange();
// Special language range ("*") is ignored in lookup.
if (range.equals("*")) {
continue;
}
String rangeForRegex = range.replace("*", "\\p{Alnum}*");
while (rangeForRegex.length() > 0) {
if (tag.matches(rangeForRegex)) {
return true;
}
// Truncate from the end....
rangeForRegex = truncateRange(rangeForRegex);
}
}
return false;
}
/* Truncate the range from end during the lookup match */
private static String truncateRange(String rangeForRegex) {
int index = rangeForRegex.lastIndexOf('-');
if (index >= 0) {
rangeForRegex = rangeForRegex.substring(0, index);
// if range ends with an extension key, truncate it.
index = rangeForRegex.lastIndexOf('-');
if (index >= 0 && index == rangeForRegex.length() - 2) {
rangeForRegex
= rangeForRegex.substring(0, rangeForRegex.length() - 2);
}
} else {
rangeForRegex = "";
}
return rangeForRegex;
}
/* Returns the split index of the priority list, if it contains
* language range(s) with quality weight as 0 i.e. q=0, else -1
*/
private static int splitRanges(List<LanguageRange> priorityList) {
int size = priorityList.size();
for (int index = 0; index < size; index++) {
LanguageRange range = priorityList.get(index);
if (range.getWeight() == 0) {
return index;
}
}
return -1; // no q=0 range exists
}
public static List<LanguageRange> parse(String ranges) {
ranges = ranges.replace(" ", "").toLowerCase(Locale.ROOT);
if (ranges.startsWith("accept-language:")) {
ranges = ranges.substring(16); // delete unnecessary prefix
}
String[] langRanges = ranges.split(",");
List<LanguageRange> list = new ArrayList<>(langRanges.length);
List<String> tempList = new ArrayList<>();
int numOfRanges = 0;
for (String range : langRanges) {
int index;
String r;
double w;
if ((index = range.indexOf(";q=")) == -1) {
r = range;
w = MAX_WEIGHT;
} else {
r = range.substring(0, index);
index += 3;
try {
w = Double.parseDouble(range.substring(index));
}
catch (Exception e) {
throw new IllegalArgumentException("weight=\""
+ range.substring(index)
+ "\" for language range \"" + r + "\"");
}
if (w < MIN_WEIGHT || w > MAX_WEIGHT) {
throw new IllegalArgumentException("weight=" + w
+ " for language range \"" + r
+ "\". It must be between " + MIN_WEIGHT
+ " and " + MAX_WEIGHT + ".");
}
}
if (!tempList.contains(r)) {
LanguageRange lr = new LanguageRange(r, w);
index = numOfRanges;
for (int j = 0; j < numOfRanges; j++) {
if (list.get(j).getWeight() < w) {
index = j;
break;
}
}
list.add(index, lr);
numOfRanges++;
tempList.add(r);
// Check if the range has an equivalent using IANA LSR data.
// If yes, add it to the User's Language Priority List as well.
// aa-XX -> aa-YY
String equivalent;
if ((equivalent = getEquivalentForRegionAndVariant(r)) != null
&& !tempList.contains(equivalent)) {
list.add(index+1, new LanguageRange(equivalent, w));
numOfRanges++;
tempList.add(equivalent);
}
String[] equivalents;
if ((equivalents = getEquivalentsForLanguage(r)) != null) {
for (String equiv: equivalents) {
// aa-XX -> bb-XX(, cc-XX)
if (!tempList.contains(equiv)) {
list.add(index+1, new LanguageRange(equiv, w));
numOfRanges++;
tempList.add(equiv);
}
// bb-XX -> bb-YY(, cc-YY)
equivalent = getEquivalentForRegionAndVariant(equiv);
if (equivalent != null
&& !tempList.contains(equivalent)) {
list.add(index+1, new LanguageRange(equivalent, w));
numOfRanges++;
tempList.add(equivalent);
}
}
}
}
}
return list;
}
/**
* A faster alternative approach to String.replaceFirst(), if the given
* string is a literal String, not a regex.
*/
private static String replaceFirstSubStringMatch(String range,
String substr, String replacement) {
int pos = range.indexOf(substr);
if (pos == -1) {
return range;
} else {
return range.substring(0, pos) + replacement
+ range.substring(pos + substr.length());
}
}
private static String[] getEquivalentsForLanguage(String range) {
String r = range;
while (r.length() > 0) {
if (LocaleEquivalentMaps.singleEquivMap.containsKey(r)) {
String equiv = LocaleEquivalentMaps.singleEquivMap.get(r);
// Return immediately for performance if the first matching
// subtag is found.
return new String[]{replaceFirstSubStringMatch(range,
r, equiv)};
} else if (LocaleEquivalentMaps.multiEquivsMap.containsKey(r)) {
String[] equivs = LocaleEquivalentMaps.multiEquivsMap.get(r);
String[] result = new String[equivs.length];
for (int i = 0; i < equivs.length; i++) {
result[i] = replaceFirstSubStringMatch(range,
r, equivs[i]);
}
return result;
}
// Truncate the last subtag simply.
int index = r.lastIndexOf('-');
if (index == -1) {
break;
}
r = r.substring(0, index);
}
return null;
}
private static String getEquivalentForRegionAndVariant(String range) {
int extensionKeyIndex = getExtentionKeyIndex(range);
for (String subtag : LocaleEquivalentMaps.regionVariantEquivMap.keySet()) {
int index;
if ((index = range.indexOf(subtag)) != -1) {
// Check if the matching text is a valid region or variant.
if (extensionKeyIndex != Integer.MIN_VALUE
&& index > extensionKeyIndex) {
continue;
}
int len = index + subtag.length();
if (range.length() == len || range.charAt(len) == '-') {
return replaceFirstSubStringMatch(range, subtag,
LocaleEquivalentMaps.regionVariantEquivMap
.get(subtag));
}
}
}
return null;
}
private static int getExtentionKeyIndex(String s) {
char[] c = s.toCharArray();
int index = Integer.MIN_VALUE;
for (int i = 1; i < c.length; i++) {
if (c[i] == '-') {
if (i - index == 2) {
return index;
} else {
index = i;
}
}
}
return Integer.MIN_VALUE;
}
public static List<LanguageRange> mapEquivalents(
List<LanguageRange>priorityList,
Map<String, List<String>> map) {
if (priorityList.isEmpty()) {
return new ArrayList<>(); // need to return a empty mutable List
}
if (map == null || map.isEmpty()) {
return new ArrayList<LanguageRange>(priorityList);
}
// Create a map, key=originalKey.toLowerCaes(), value=originalKey
Map<String, String> keyMap = new HashMap<>();
for (String key : map.keySet()) {
keyMap.put(key.toLowerCase(Locale.ROOT), key);
}
List<LanguageRange> list = new ArrayList<>();
for (LanguageRange lr : priorityList) {
String range = lr.getRange();
String r = range;
boolean hasEquivalent = false;
while (r.length() > 0) {
if (keyMap.containsKey(r)) {
hasEquivalent = true;
List<String> equivalents = map.get(keyMap.get(r));
if (equivalents != null) {
int len = r.length();
for (String equivalent : equivalents) {
list.add(new LanguageRange(equivalent.toLowerCase(Locale.ROOT)
+ range.substring(len),
lr.getWeight()));
}
}
// Return immediately if the first matching subtag is found.
break;
}
// Truncate the last subtag simply.
int index = r.lastIndexOf('-');
if (index == -1) {
break;
}
r = r.substring(0, index);
}
if (!hasEquivalent) {
list.add(lr);
}
}
return list;
}
private LocaleMatcher() {}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public abstract class LocaleObjectCache<K, V> {
private ConcurrentMap<K, CacheEntry<K, V>> map;
private ReferenceQueue<V> queue = new ReferenceQueue<>();
public LocaleObjectCache() {
this(16, 0.75f, 16);
}
public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) {
map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
}
public V get(K key) {
V value = null;
cleanStaleEntries();
CacheEntry<K, V> entry = map.get(key);
if (entry != null) {
value = entry.get();
}
if (value == null) {
V newVal = createObject(key);
// make sure key is normalized *after* the object creation
// so that newVal is assured to be created from a valid key.
key = normalizeKey(key);
if (key == null || newVal == null) {
// subclass must return non-null key/value object
return null;
}
CacheEntry<K, V> newEntry = new CacheEntry<>(key, newVal, queue);
entry = map.putIfAbsent(key, newEntry);
if (entry == null) {
value = newVal;
} else {
value = entry.get();
if (value == null) {
map.put(key, newEntry);
value = newVal;
}
}
}
return value;
}
protected V put(K key, V value) {
CacheEntry<K, V> entry = new CacheEntry<>(key, value, queue);
CacheEntry<K, V> oldEntry = map.put(key, entry);
return (oldEntry == null) ? null : oldEntry.get();
}
@SuppressWarnings("unchecked")
private void cleanStaleEntries() {
CacheEntry<K, V> entry;
while ((entry = (CacheEntry<K, V>)queue.poll()) != null) {
map.remove(entry.getKey());
}
}
protected abstract V createObject(K key);
protected K normalizeKey(K key) {
return key;
}
private static class CacheEntry<K, V> extends SoftReference<V> {
private K key;
CacheEntry(K key, V value, ReferenceQueue<V> queue) {
super(value, queue);
this.key = key;
}
K getKey() {
return key;
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
public class LocaleSyntaxException extends Exception {
private static final long serialVersionUID = 1L;
private int index = -1;
public LocaleSyntaxException(String msg) {
this(msg, 0);
}
public LocaleSyntaxException(String msg, int errorIndex) {
super(msg);
index = errorIndex;
}
public int getErrorIndex() {
return index;
}
}

View file

@ -0,0 +1,224 @@
/*
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Collection of static utility methods for Locale support. The
* methods which manipulate characters or strings support ASCII only.
*/
public final class LocaleUtils {
private LocaleUtils() {
}
/**
* Compares two ASCII Strings s1 and s2, ignoring case.
*/
public static boolean caseIgnoreMatch(String s1, String s2) {
if (s1 == s2) {
return true;
}
int len = s1.length();
if (len != s2.length()) {
return false;
}
for (int i = 0; i < len; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2 && toLower(c1) != toLower(c2)) {
return false;
}
}
return true;
}
static int caseIgnoreCompare(String s1, String s2) {
if (s1 == s2) {
return 0;
}
return toLowerString(s1).compareTo(toLowerString(s2));
}
static char toUpper(char c) {
return isLower(c) ? (char)(c - 0x20) : c;
}
static char toLower(char c) {
return isUpper(c) ? (char)(c + 0x20) : c;
}
/**
* Converts the given ASCII String to lower-case.
*/
public static String toLowerString(String s) {
int len = s.length();
int idx = 0;
for (; idx < len; idx++) {
if (isUpper(s.charAt(idx))) {
break;
}
}
if (idx == len) {
return s;
}
char[] buf = new char[len];
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
buf[i] = (i < idx) ? c : toLower(c);
}
return new String(buf);
}
static String toUpperString(String s) {
int len = s.length();
int idx = 0;
for (; idx < len; idx++) {
if (isLower(s.charAt(idx))) {
break;
}
}
if (idx == len) {
return s;
}
char[] buf = new char[len];
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
buf[i] = (i < idx) ? c : toUpper(c);
}
return new String(buf);
}
static String toTitleString(String s) {
int len;
if ((len = s.length()) == 0) {
return s;
}
int idx = 0;
if (!isLower(s.charAt(idx))) {
for (idx = 1; idx < len; idx++) {
if (isUpper(s.charAt(idx))) {
break;
}
}
}
if (idx == len) {
return s;
}
char[] buf = new char[len];
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (i == 0 && idx == 0) {
buf[i] = toUpper(c);
} else if (i < idx) {
buf[i] = c;
} else {
buf[i] = toLower(c);
}
}
return new String(buf);
}
private static boolean isUpper(char c) {
return c >= 'A' && c <= 'Z';
}
private static boolean isLower(char c) {
return c >= 'a' && c <= 'z';
}
static boolean isAlpha(char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
static boolean isAlphaString(String s) {
int len = s.length();
for (int i = 0; i < len; i++) {
if (!isAlpha(s.charAt(i))) {
return false;
}
}
return true;
}
static boolean isNumeric(char c) {
return (c >= '0' && c <= '9');
}
static boolean isNumericString(String s) {
int len = s.length();
for (int i = 0; i < len; i++) {
if (!isNumeric(s.charAt(i))) {
return false;
}
}
return true;
}
static boolean isAlphaNumeric(char c) {
return isAlpha(c) || isNumeric(c);
}
public static boolean isAlphaNumericString(String s) {
int len = s.length();
for (int i = 0; i < len; i++) {
if (!isAlphaNumeric(s.charAt(i))) {
return false;
}
}
return true;
}
static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
static boolean isEmpty(Set<?> set) {
return set == null || set.isEmpty();
}
static boolean isEmpty(Map<?, ?> map) {
return map == null || map.isEmpty();
}
static boolean isEmpty(List<?> list) {
return list == null || list.isEmpty();
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
public class ParseStatus {
int parseLength;
int errorIndex;
String errorMsg;
public ParseStatus() {
reset();
}
public void reset() {
parseLength = 0;
errorIndex = -1;
errorMsg = null;
}
public boolean isError() {
return (errorIndex >= 0);
}
public int getErrorIndex() {
return errorIndex;
}
public int getParseLength() {
return parseLength;
}
public String getErrorMessage() {
return errorMsg;
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
public class StringTokenIterator {
private String text;
private String dlms; // null if a single char delimiter
private char delimiterChar; // delimiter if a single char delimiter
private String token;
private int start;
private int end;
private boolean done;
public StringTokenIterator(String text, String dlms) {
this.text = text;
if (dlms.length() == 1) {
delimiterChar = dlms.charAt(0);
} else {
this.dlms = dlms;
}
setStart(0);
}
public String first() {
setStart(0);
return token;
}
public String current() {
return token;
}
public int currentStart() {
return start;
}
public int currentEnd() {
return end;
}
public boolean isDone() {
return done;
}
public String next() {
if (hasNext()) {
start = end + 1;
end = nextDelimiter(start);
token = text.substring(start, end);
} else {
start = end;
token = null;
done = true;
}
return token;
}
public boolean hasNext() {
return (end < text.length());
}
public StringTokenIterator setStart(int offset) {
if (offset > text.length()) {
throw new IndexOutOfBoundsException();
}
start = offset;
end = nextDelimiter(start);
token = text.substring(start, end);
done = false;
return this;
}
public StringTokenIterator setText(String text) {
this.text = text;
setStart(0);
return this;
}
private int nextDelimiter(int start) {
int textlen = this.text.length();
if (dlms == null) {
for (int idx = start; idx < textlen; idx++) {
if (text.charAt(idx) == delimiterChar) {
return idx;
}
}
} else {
int dlmslen = dlms.length();
for (int idx = start; idx < textlen; idx++) {
char c = text.charAt(idx);
for (int i = 0; i < dlmslen; i++) {
if (c == dlms.charAt(i)) {
return idx;
}
}
}
}
return textlen;
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package sun.util.locale;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.StringJoiner;
public class UnicodeLocaleExtension extends Extension {
public static final char SINGLETON = 'u';
private final Set<String> attributes;
private final Map<String, String> keywords;
public static final UnicodeLocaleExtension CA_JAPANESE
= new UnicodeLocaleExtension("ca", "japanese");
public static final UnicodeLocaleExtension NU_THAI
= new UnicodeLocaleExtension("nu", "thai");
private UnicodeLocaleExtension(String key, String value) {
super(SINGLETON, key + "-" + value);
attributes = Collections.emptySet();
keywords = Collections.singletonMap(key, value);
}
UnicodeLocaleExtension(SortedSet<String> attributes, SortedMap<String, String> keywords) {
super(SINGLETON);
if (attributes != null) {
this.attributes = attributes;
} else {
this.attributes = Collections.emptySet();
}
if (keywords != null) {
this.keywords = keywords;
} else {
this.keywords = Collections.emptyMap();
}
if (!this.attributes.isEmpty() || !this.keywords.isEmpty()) {
StringJoiner sj = new StringJoiner(LanguageTag.SEP);
for (String attribute : this.attributes) {
sj.add(attribute);
}
for (Entry<String, String> keyword : this.keywords.entrySet()) {
String key = keyword.getKey();
String value = keyword.getValue();
sj.add(key);
if (value.length() > 0) {
sj.add(value);
}
}
setValue(sj.toString());
}
}
public Set<String> getUnicodeLocaleAttributes() {
if (attributes == Collections.EMPTY_SET) {
return attributes;
}
return Collections.unmodifiableSet(attributes);
}
public Set<String> getUnicodeLocaleKeys() {
if (keywords == Collections.EMPTY_MAP) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(keywords.keySet());
}
public String getUnicodeLocaleType(String unicodeLocaleKey) {
return keywords.get(unicodeLocaleKey);
}
public static boolean isSingletonChar(char c) {
return (SINGLETON == LocaleUtils.toLower(c));
}
public static boolean isAttribute(String s) {
// 3*8alphanum
int len = s.length();
return (len >= 3) && (len <= 8) && LocaleUtils.isAlphaNumericString(s);
}
public static boolean isKey(String s) {
// 2alphanum
return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
}
public static boolean isTypeSubtag(String s) {
// 3*8alphanum
int len = s.length();
return (len >= 3) && (len <= 8) && LocaleUtils.isAlphaNumericString(s);
}
}

View file

@ -0,0 +1,198 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.text.spi.DateFormatProvider;
import java.text.spi.DateFormatSymbolsProvider;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.text.spi.NumberFormatProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import java.util.spi.LocaleServiceProvider;
import java.util.spi.TimeZoneNameProvider;
import sun.text.spi.JavaTimeDateTimePatternProvider;
import sun.util.spi.CalendarProvider;
/**
* An abstract parent class for the
* HostLocaleProviderAdapter/SPILocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public abstract class AuxLocaleProviderAdapter extends LocaleProviderAdapter {
/**
* SPI implementations map
*/
private final ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProvider> providersMap =
new ConcurrentHashMap<>();
/**
* Getter method for Locale Service Providers
*/
@Override
public <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c) {
@SuppressWarnings("unchecked")
P lsp = (P) providersMap.get(c);
if (lsp == null) {
lsp = findInstalledProvider(c);
providersMap.putIfAbsent(c, lsp == null ? NULL_PROVIDER : lsp);
}
return lsp;
}
/**
* Real body to find an implementation for each SPI.
*
* @param <P>
* @param c
* @return
*/
protected abstract <P extends LocaleServiceProvider> P findInstalledProvider(final Class<P> c);
@Override
public BreakIteratorProvider getBreakIteratorProvider() {
return getLocaleServiceProvider(BreakIteratorProvider.class);
}
@Override
public CollatorProvider getCollatorProvider() {
return getLocaleServiceProvider(CollatorProvider.class);
}
@Override
public DateFormatProvider getDateFormatProvider() {
return getLocaleServiceProvider(DateFormatProvider.class);
}
@Override
public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
return getLocaleServiceProvider(DateFormatSymbolsProvider.class);
}
@Override
public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
return getLocaleServiceProvider(DecimalFormatSymbolsProvider.class);
}
@Override
public NumberFormatProvider getNumberFormatProvider() {
return getLocaleServiceProvider(NumberFormatProvider.class);
}
/**
* Getter methods for java.util.spi.* providers
*/
@Override
public CurrencyNameProvider getCurrencyNameProvider() {
return getLocaleServiceProvider(CurrencyNameProvider.class);
}
@Override
public LocaleNameProvider getLocaleNameProvider() {
return getLocaleServiceProvider(LocaleNameProvider.class);
}
@Override
public TimeZoneNameProvider getTimeZoneNameProvider() {
return getLocaleServiceProvider(TimeZoneNameProvider.class);
}
@Override
public CalendarDataProvider getCalendarDataProvider() {
return getLocaleServiceProvider(CalendarDataProvider.class);
}
@Override
public CalendarNameProvider getCalendarNameProvider() {
return getLocaleServiceProvider(CalendarNameProvider.class);
}
/**
* Getter methods for sun.util.spi.* providers
*/
@Override
public CalendarProvider getCalendarProvider() {
return getLocaleServiceProvider(CalendarProvider.class);
}
@Override
public LocaleResources getLocaleResources(Locale locale) {
return null;
}
@Override
public JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
return getLocaleServiceProvider(JavaTimeDateTimePatternProvider.class);
}
private static Locale[] availableLocales = null;
@Override
public Locale[] getAvailableLocales() {
if (availableLocales == null) {
List<Locale> avail = new ArrayList<>();
for (Class<? extends LocaleServiceProvider> c :
LocaleServiceProviderPool.spiClasses) {
LocaleServiceProvider lsp = getLocaleServiceProvider(c);
if (lsp != null) {
avail.addAll(Arrays.asList(lsp.getAvailableLocales()));
}
}
availableLocales = avail.toArray(new Locale[0]);
}
// assuming caller won't mutate the array.
return availableLocales;
}
/**
* A dummy locale service provider that indicates there is no
* provider available
*/
private static final NullProvider NULL_PROVIDER = AccessController.doPrivileged(
(PrivilegedAction<NullProvider>) () -> new NullProvider());
private static class NullProvider extends LocaleServiceProvider {
@Override
public Locale[] getAvailableLocales() {
return new Locale[0];
}
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Set;
/**
* An interface to return a set of available language tags supported by a
* LocaleServiceProvider.
*
* @author Masayoshi Okutsu
*/
public interface AvailableLanguageTags {
/**
* Returns a set of available language tags of a LocaleServiceProvider.
* Note that the returned set doesn't contain the language tag for
* {@code Locale.Root}.
*
* @return a Set of available language tags.
*/
public Set<String> getAvailableLanguageTags();
}

View file

@ -0,0 +1,196 @@
/*
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.io.IOException;
import java.text.BreakIterator;
import java.text.spi.BreakIteratorProvider;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Set;
import sun.text.DictionaryBasedBreakIterator;
import sun.text.RuleBasedBreakIterator;
/**
* Concrete implementation of the {@link java.text.spi.BreakIteratorProvider
* BreakIteratorProvider} class for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class BreakIteratorProviderImpl extends BreakIteratorProvider
implements AvailableLanguageTags {
private static final int CHARACTER_INDEX = 0;
private static final int WORD_INDEX = 1;
private static final int LINE_INDEX = 2;
private static final int SENTENCE_INDEX = 3;
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public BreakIteratorProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
/**
* Returns a new <code>BreakIterator</code> instance
* for <a href="../BreakIterator.html#word">word breaks</a>
* for the given locale.
* @param locale the desired locale
* @return A break iterator for word breaks
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.text.BreakIterator#getWordInstance(java.util.Locale)
*/
@Override
public BreakIterator getWordInstance(Locale locale) {
return getBreakInstance(locale,
WORD_INDEX,
"WordData",
"WordDictionary");
}
/**
* Returns a new <code>BreakIterator</code> instance
* for <a href="../BreakIterator.html#line">line breaks</a>
* for the given locale.
* @param locale the desired locale
* @return A break iterator for line breaks
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.text.BreakIterator#getLineInstance(java.util.Locale)
*/
@Override
public BreakIterator getLineInstance(Locale locale) {
return getBreakInstance(locale,
LINE_INDEX,
"LineData",
"LineDictionary");
}
/**
* Returns a new <code>BreakIterator</code> instance
* for <a href="../BreakIterator.html#character">character breaks</a>
* for the given locale.
* @param locale the desired locale
* @return A break iterator for character breaks
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.text.BreakIterator#getCharacterInstance(java.util.Locale)
*/
@Override
public BreakIterator getCharacterInstance(Locale locale) {
return getBreakInstance(locale,
CHARACTER_INDEX,
"CharacterData",
"CharacterDictionary");
}
/**
* Returns a new <code>BreakIterator</code> instance
* for <a href="../BreakIterator.html#sentence">sentence breaks</a>
* for the given locale.
* @param locale the desired locale
* @return A break iterator for sentence breaks
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.text.BreakIterator#getSentenceInstance(java.util.Locale)
*/
@Override
public BreakIterator getSentenceInstance(Locale locale) {
return getBreakInstance(locale,
SENTENCE_INDEX,
"SentenceData",
"SentenceDictionary");
}
private BreakIterator getBreakInstance(Locale locale,
int type,
String ruleName,
String dictionaryName) {
Objects.requireNonNull(locale);
LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses");
String ruleFile = (String) lr.getBreakIteratorInfo(ruleName);
byte[] ruleData = lr.getBreakIteratorResources(ruleName);
try {
switch (classNames[type]) {
case "RuleBasedBreakIterator":
return new RuleBasedBreakIterator(ruleFile, ruleData);
case "DictionaryBasedBreakIterator":
String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName);
byte[] dictionaryData = lr.getBreakIteratorResources(dictionaryName);
return new DictionaryBasedBreakIterator(ruleFile, ruleData,
dictionaryFile, dictionaryData);
default:
throw new IllegalArgumentException("Invalid break iterator class \"" +
classNames[type] + "\"");
}
} catch (MissingResourceException | IllegalArgumentException e) {
throw new InternalError(e.toString(), e);
}
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Locale;
import java.util.Set;
import java.util.spi.CalendarDataProvider;
/**
* Concrete implementation of the {@link java.util.spi.CalendarDataProvider
* CalendarDataProvider} class for the JRE LocaleProviderAdapter.
*
* @author Masayoshi Okutsu
* @author Naoto Sato
*/
public class CalendarDataProviderImpl extends CalendarDataProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public CalendarDataProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
@Override
public int getFirstDayOfWeek(Locale locale) {
return LocaleProviderAdapter.forType(type).getLocaleResources(locale)
.getCalendarData(CalendarDataUtility.FIRST_DAY_OF_WEEK);
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
return LocaleProviderAdapter.forType(type).getLocaleResources(locale)
.getCalendarData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK);
}
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,208 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import static java.util.Calendar.*;
import java.util.Locale;
import java.util.Map;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
/**
* {@code CalendarDataUtility} is a utility class for calling the
* {@link CalendarDataProvider} methods.
*
* @author Masayoshi Okutsu
* @author Naoto Sato
*/
public class CalendarDataUtility {
public static final String FIRST_DAY_OF_WEEK = "firstDayOfWeek";
public static final String MINIMAL_DAYS_IN_FIRST_WEEK = "minimalDaysInFirstWeek";
// No instantiation
private CalendarDataUtility() {
}
public static int retrieveFirstDayOfWeek(Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarDataProvider.class);
Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE,
locale, true, FIRST_DAY_OF_WEEK);
return (value != null && (value >= SUNDAY && value <= SATURDAY)) ? value : SUNDAY;
}
public static int retrieveMinimalDaysInFirstWeek(Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarDataProvider.class);
Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE,
locale, true, MINIMAL_DAYS_IN_FIRST_WEEK);
return (value != null && (value >= 1 && value <= 7)) ? value : 1;
}
public static String retrieveFieldValueName(String id, int field, int value, int style, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarNameProvider.class);
return pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id),
field, value, style, false);
}
public static String retrieveJavaTimeFieldValueName(String id, int field, int value, int style, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarNameProvider.class);
String name;
name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id),
field, value, style, true);
if (name == null) {
name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id),
field, value, style, false);
}
return name;
}
public static Map<String, Integer> retrieveFieldValueNames(String id, int field, int style, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarNameProvider.class);
return pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale,
normalizeCalendarType(id), field, style, false);
}
public static Map<String, Integer> retrieveJavaTimeFieldValueNames(String id, int field, int style, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(CalendarNameProvider.class);
Map<String, Integer> map;
map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale,
normalizeCalendarType(id), field, style, true);
if (map == null) {
map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale,
normalizeCalendarType(id), field, style, false);
}
return map;
}
static String normalizeCalendarType(String requestID) {
String type;
if (requestID.equals("gregorian") || requestID.equals("iso8601")) {
type = "gregory";
} else if (requestID.startsWith("islamic")) {
type = "islamic";
} else {
type = requestID;
}
return type;
}
/**
* Obtains a localized field value string from a CalendarDataProvider
* implementation.
*/
private static class CalendarFieldValueNameGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarNameProvider,
String> {
private static final CalendarFieldValueNameGetter INSTANCE =
new CalendarFieldValueNameGetter();
@Override
public String getObject(CalendarNameProvider calendarNameProvider,
Locale locale,
String requestID, // calendarType
Object... params) {
assert params.length == 4;
int field = (int) params[0];
int value = (int) params[1];
int style = (int) params[2];
boolean javatime = (boolean) params[3];
// If javatime is true, resources from CLDR have precedence over JRE
// native resources.
if (javatime && calendarNameProvider instanceof CalendarNameProviderImpl) {
String name;
name = ((CalendarNameProviderImpl)calendarNameProvider)
.getJavaTimeDisplayName(requestID, field, value, style, locale);
return name;
}
return calendarNameProvider.getDisplayName(requestID, field, value, style, locale);
}
}
/**
* Obtains a localized field-value pairs from a CalendarDataProvider
* implementation.
*/
private static class CalendarFieldValueNamesMapGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarNameProvider,
Map<String, Integer>> {
private static final CalendarFieldValueNamesMapGetter INSTANCE =
new CalendarFieldValueNamesMapGetter();
@Override
public Map<String, Integer> getObject(CalendarNameProvider calendarNameProvider,
Locale locale,
String requestID, // calendarType
Object... params) {
assert params.length == 3;
int field = (int) params[0];
int style = (int) params[1];
boolean javatime = (boolean) params[2];
// If javatime is true, resources from CLDR have precedence over JRE
// native resources.
if (javatime && calendarNameProvider instanceof CalendarNameProviderImpl) {
Map<String, Integer> map;
map = ((CalendarNameProviderImpl)calendarNameProvider)
.getJavaTimeDisplayNames(requestID, field, style, locale);
return map;
}
return calendarNameProvider.getDisplayNames(requestID, field, style, locale);
}
}
private static class CalendarWeekParameterGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarDataProvider,
Integer> {
private static final CalendarWeekParameterGetter INSTANCE =
new CalendarWeekParameterGetter();
@Override
public Integer getObject(CalendarDataProvider calendarDataProvider,
Locale locale,
String requestID, // resource key
Object... params) {
assert params.length == 0;
int value;
switch (requestID) {
case FIRST_DAY_OF_WEEK:
value = calendarDataProvider.getFirstDayOfWeek(locale);
break;
case MINIMAL_DAYS_IN_FIRST_WEEK:
value = calendarDataProvider.getMinimalDaysInFirstWeek(locale);
break;
default:
throw new InternalError("invalid requestID: " + requestID);
}
return (value != 0) ? value : null;
}
}
}

View file

@ -0,0 +1,348 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import static java.util.Calendar.*;
import java.util.Comparator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.spi.CalendarNameProvider;
import sun.util.calendar.CalendarSystem;
import sun.util.calendar.Era;
/**
* Concrete implementation of the {@link java.util.spi.CalendarDataProvider
* CalendarDataProvider} class for the JRE LocaleProviderAdapter.
*
* @author Masayoshi Okutsu
* @author Naoto Sato
*/
public class CalendarNameProviderImpl extends CalendarNameProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public CalendarNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
@Override
public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) {
return getDisplayNameImpl(calendarType, field, value, style, locale, false);
}
public String getJavaTimeDisplayName(String calendarType, int field, int value, int style, Locale locale) {
return getDisplayNameImpl(calendarType, field, value, style, locale, true);
}
public String getDisplayNameImpl(String calendarType, int field, int value, int style, Locale locale, boolean javatime) {
String name = null;
String key = getResourceKey(calendarType, field, style, javatime);
if (key != null) {
LocaleResources lr = LocaleProviderAdapter.forType(type).getLocaleResources(locale);
String[] strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
// If standalone names are requested and no "standalone." resources are found,
// try the default ones instead.
if (strings == null && key.indexOf("standalone.") != -1) {
key = key.replaceFirst("standalone.", "");
strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
}
if (strings != null && strings.length > 0) {
if (field == DAY_OF_WEEK || field == YEAR) {
--value;
}
if (value < 0 || value > strings.length) {
return null;
} else if (value == strings.length) {
if (field == ERA && "japanese".equals(calendarType)) {
// get the supplemental era, if any, specified through
// the property "jdk.calendar.japanese.supplemental.era"
// which is always the last element.
Era[] jeras = CalendarSystem.forName("japanese").getEras();
if (jeras.length == value) {
Era supEra = jeras[value - 1]; // 0-based index
if (javatime) {
return getBaseStyle(style) == NARROW_FORMAT ?
supEra.getAbbreviation() :
supEra.getName();
} else {
return (style & LONG) != 0 ?
supEra.getName() :
supEra.getAbbreviation();
}
}
}
return null;
}
name = strings[value];
// If name is empty in standalone, try its `format' style.
if (name.length() == 0
&& (style == SHORT_STANDALONE || style == LONG_STANDALONE
|| style == NARROW_STANDALONE)) {
name = getDisplayName(calendarType, field, value,
getBaseStyle(style),
locale);
}
}
}
return name;
}
private static int[] REST_OF_STYLES = {
SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE,
NARROW_FORMAT, NARROW_STANDALONE
};
@Override
public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) {
Map<String, Integer> names;
if (style == ALL_STYLES) {
names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale, false);
for (int st : REST_OF_STYLES) {
names.putAll(getDisplayNamesImpl(calendarType, field, st, locale, false));
}
} else {
// specific style
names = getDisplayNamesImpl(calendarType, field, style, locale, false);
}
return names.isEmpty() ? null : names;
}
// NOTE: This method should be used ONLY BY JSR 310 classes.
public Map<String, Integer> getJavaTimeDisplayNames(String calendarType, int field, int style, Locale locale) {
Map<String, Integer> names;
names = getDisplayNamesImpl(calendarType, field, style, locale, true);
return names.isEmpty() ? null : names;
}
private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field,
int style, Locale locale, boolean javatime) {
String key = getResourceKey(calendarType, field, style, javatime);
Map<String, Integer> map = new TreeMap<>(LengthBasedComparator.INSTANCE);
if (key != null) {
LocaleResources lr = LocaleProviderAdapter.forType(type).getLocaleResources(locale);
String[] strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
// If standalone names are requested and no "standalone." resources are found,
// try the default ones instead.
if (strings == null && key.indexOf("standalone.") != -1) {
key = key.replaceFirst("standalone.", "");
strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
}
if (strings != null) {
if (!hasDuplicates(strings)) {
if (field == YEAR) {
if (strings.length > 0) {
map.put(strings[0], 1);
}
} else {
int base = (field == DAY_OF_WEEK) ? 1 : 0;
for (int i = 0; i < strings.length; i++) {
String name = strings[i];
// Ignore any empty string (some standalone month names
// are not defined)
if (name.length() == 0) {
continue;
}
map.put(name, base + i);
}
}
}
}
}
return map;
}
private int getBaseStyle(int style) {
return style & ~(SHORT_STANDALONE - SHORT_FORMAT);
}
/**
* Comparator implementation for TreeMap which iterates keys from longest
* to shortest.
*/
private static class LengthBasedComparator implements Comparator<String> {
private static final LengthBasedComparator INSTANCE = new LengthBasedComparator();
private LengthBasedComparator() {
}
@Override
public int compare(String o1, String o2) {
int n = o2.length() - o1.length();
return (n == 0) ? o1.compareTo(o2) : n;
}
}
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
if (Locale.ROOT.equals(locale)) {
return true;
}
String calendarType = null;
if (locale.hasExtensions()) {
calendarType = locale.getUnicodeLocaleType("ca");
locale = locale.stripExtensions();
}
if (calendarType != null) {
switch (calendarType) {
case "buddhist":
case "japanese":
case "gregory":
case "islamic":
case "roc":
break;
default:
// Unknown calendar type
return false;
}
}
if (langtags.contains(locale.toLanguageTag())) {
return true;
}
if (type == LocaleProviderAdapter.Type.JRE) {
String oldname = locale.toString().replace('_', '-');
return langtags.contains(oldname);
}
return false;
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
private boolean hasDuplicates(String[] strings) {
int len = strings.length;
for (int i = 0; i < len - 1; i++) {
String a = strings[i];
if (a != null) {
for (int j = i + 1; j < len; j++) {
if (a.equals(strings[j])) {
return true;
}
}
}
}
return false;
}
private String getResourceKey(String type, int field, int style, boolean javatime) {
int baseStyle = getBaseStyle(style);
boolean isStandalone = (style != baseStyle);
if ("gregory".equals(type)) {
type = null;
}
boolean isNarrow = (baseStyle == NARROW_FORMAT);
StringBuilder key = new StringBuilder();
// If javatime is true, use prefix "java.time.".
if (javatime) {
key.append("java.time.");
}
switch (field) {
case ERA:
if (type != null) {
key.append(type).append('.');
}
if (isNarrow) {
key.append("narrow.");
} else {
// JRE and CLDR use different resource key conventions
// due to historical reasons. (JRE DateFormatSymbols.getEras returns
// abbreviations while other getShort*() return abbreviations.)
if (this.type == LocaleProviderAdapter.Type.JRE) {
if (javatime) {
if (baseStyle == LONG) {
key.append("long.");
}
}
if (baseStyle == SHORT) {
key.append("short.");
}
} else { // this.type == LocaleProviderAdapter.Type.CLDR
if (baseStyle == LONG) {
key.append("long.");
}
}
}
key.append("Eras");
break;
case YEAR:
if (!isNarrow) {
key.append(type).append(".FirstYear");
}
break;
case MONTH:
if ("islamic".equals(type)) {
key.append(type).append('.');
}
if (isStandalone) {
key.append("standalone.");
}
key.append("Month").append(toStyleName(baseStyle));
break;
case DAY_OF_WEEK:
// support standalone day names
if (isStandalone) {
key.append("standalone.");
}
key.append("Day").append(toStyleName(baseStyle));
break;
case AM_PM:
if (isNarrow) {
key.append("narrow.");
}
key.append("AmPmMarkers");
break;
}
return key.length() > 0 ? key.toString() : null;
}
private String toStyleName(int baseStyle) {
switch (baseStyle) {
case SHORT:
return "Abbreviations";
case NARROW_FORMAT:
return "Narrows";
}
return "Names";
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Calendar;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import sun.util.spi.CalendarProvider;
/**
* Concrete implementation of the {@link sun.util.spi.CalendarProvider
* CalendarProvider} class for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
*/
public class CalendarProviderImpl extends CalendarProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public CalendarProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
// Support any locales.
return true;
}
/**
* Returns a new <code>Calendar</code> instance for the
* specified locale.
*
* @param zone the time zone
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a <code>Calendar</code> instance.
* @see java.util.Calendar#getInstance(java.util.Locale)
*/
@Override
public Calendar getInstance(TimeZone zone, Locale locale) {
return new Calendar.Builder()
.setLocale(locale)
.setTimeZone(zone)
.setInstant(System.currentTimeMillis())
.build();
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,277 @@
/*
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996,1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
*
* The original version of this source code and documentation is copyrighted
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
* materials are provided under terms of a License Agreement between Taligent
* and Sun. This technology is protected by multiple US and International
* patents. This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.locale.provider;
/**
* CollationRules contains the default en_US collation rules as a base
* for building other collation tables.
* <p>Note that decompositions are done before these rules are used,
* so they do not have to contain accented characters, such as A-grave.
* @see RuleBasedCollator
* @see LocaleElements
* @author Helena Shih, Mark Davis
*/
final class CollationRules {
static final String DEFAULTRULES =
"" // no FRENCH accent order by default, add in French Delta
// IGNORABLES (up to first < character)
// COMPLETELY IGNORE format characters
+ "='\u200B'=\u200C=\u200D=\u200E=\u200F"
// Control Characters
+ "=\u0000 =\u0001 =\u0002 =\u0003 =\u0004" //null, .. eot
+ "=\u0005 =\u0006 =\u0007 =\u0008 ='\u0009'" //enq, ...
+ "='\u000b' =\u000e" //vt,, so
+ "=\u000f ='\u0010' =\u0011 =\u0012 =\u0013" //si, dle, dc1, dc2, dc3
+ "=\u0014 =\u0015 =\u0016 =\u0017 =\u0018" //dc4, nak, syn, etb, can
+ "=\u0019 =\u001a =\u001b =\u001c =\u001d" //em, sub, esc, fs, gs
+ "=\u001e =\u001f =\u007f" //rs, us, del
//....then the C1 Latin 1 reserved control codes
+ "=\u0080 =\u0081 =\u0082 =\u0083 =\u0084 =\u0085"
+ "=\u0086 =\u0087 =\u0088 =\u0089 =\u008a =\u008b"
+ "=\u008c =\u008d =\u008e =\u008f =\u0090 =\u0091"
+ "=\u0092 =\u0093 =\u0094 =\u0095 =\u0096 =\u0097"
+ "=\u0098 =\u0099 =\u009a =\u009b =\u009c =\u009d"
+ "=\u009e =\u009f"
// IGNORE except for secondary, tertiary difference
// Spaces
+ ";'\u0020';'\u00A0'" // spaces
+ ";'\u2000';'\u2001';'\u2002';'\u2003';'\u2004'" // spaces
+ ";'\u2005';'\u2006';'\u2007';'\u2008';'\u2009'" // spaces
+ ";'\u200A';'\u3000';'\uFEFF'" // spaces
+ ";'\r' ;'\t' ;'\n';'\f';'\u000b'" // whitespace
// Non-spacing accents
+ ";\u0301" // non-spacing acute accent
+ ";\u0300" // non-spacing grave accent
+ ";\u0306" // non-spacing breve accent
+ ";\u0302" // non-spacing circumflex accent
+ ";\u030c" // non-spacing caron/hacek accent
+ ";\u030a" // non-spacing ring above accent
+ ";\u030d" // non-spacing vertical line above
+ ";\u0308" // non-spacing diaeresis accent
+ ";\u030b" // non-spacing double acute accent
+ ";\u0303" // non-spacing tilde accent
+ ";\u0307" // non-spacing dot above/overdot accent
+ ";\u0304" // non-spacing macron accent
+ ";\u0337" // non-spacing short slash overlay (overstruck diacritic)
+ ";\u0327" // non-spacing cedilla accent
+ ";\u0328" // non-spacing ogonek accent
+ ";\u0323" // non-spacing dot-below/underdot accent
+ ";\u0332" // non-spacing underscore/underline accent
// with the rest of the general diacritical marks in binary order
+ ";\u0305" // non-spacing overscore/overline
+ ";\u0309" // non-spacing hook above
+ ";\u030e" // non-spacing double vertical line above
+ ";\u030f" // non-spacing double grave
+ ";\u0310" // non-spacing chandrabindu
+ ";\u0311" // non-spacing inverted breve
+ ";\u0312" // non-spacing turned comma above/cedilla above
+ ";\u0313" // non-spacing comma above
+ ";\u0314" // non-spacing reversed comma above
+ ";\u0315" // non-spacing comma above right
+ ";\u0316" // non-spacing grave below
+ ";\u0317" // non-spacing acute below
+ ";\u0318" // non-spacing left tack below
+ ";\u0319" // non-spacing tack below
+ ";\u031a" // non-spacing left angle above
+ ";\u031b" // non-spacing horn
+ ";\u031c" // non-spacing left half ring below
+ ";\u031d" // non-spacing up tack below
+ ";\u031e" // non-spacing down tack below
+ ";\u031f" // non-spacing plus sign below
+ ";\u0320" // non-spacing minus sign below
+ ";\u0321" // non-spacing palatalized hook below
+ ";\u0322" // non-spacing retroflex hook below
+ ";\u0324" // non-spacing double dot below
+ ";\u0325" // non-spacing ring below
+ ";\u0326" // non-spacing comma below
+ ";\u0329" // non-spacing vertical line below
+ ";\u032a" // non-spacing bridge below
+ ";\u032b" // non-spacing inverted double arch below
+ ";\u032c" // non-spacing hacek below
+ ";\u032d" // non-spacing circumflex below
+ ";\u032e" // non-spacing breve below
+ ";\u032f" // non-spacing inverted breve below
+ ";\u0330" // non-spacing tilde below
+ ";\u0331" // non-spacing macron below
+ ";\u0333" // non-spacing double underscore
+ ";\u0334" // non-spacing tilde overlay
+ ";\u0335" // non-spacing short bar overlay
+ ";\u0336" // non-spacing long bar overlay
+ ";\u0338" // non-spacing long slash overlay
+ ";\u0339" // non-spacing right half ring below
+ ";\u033a" // non-spacing inverted bridge below
+ ";\u033b" // non-spacing square below
+ ";\u033c" // non-spacing seagull below
+ ";\u033d" // non-spacing x above
+ ";\u033e" // non-spacing vertical tilde
+ ";\u033f" // non-spacing double overscore
//+ ";\u0340" // non-spacing grave tone mark == \u0300
//+ ";\u0341" // non-spacing acute tone mark == \u0301
+ ";\u0342;"
//+ "\u0343;" // == \u0313
+ "\u0344;\u0345;\u0360;\u0361" // newer
+ ";\u0483;\u0484;\u0485;\u0486" // Cyrillic accents
+ ";\u20D0;\u20D1;\u20D2" // symbol accents
+ ";\u20D3;\u20D4;\u20D5" // symbol accents
+ ";\u20D6;\u20D7;\u20D8" // symbol accents
+ ";\u20D9;\u20DA;\u20DB" // symbol accents
+ ";\u20DC;\u20DD;\u20DE" // symbol accents
+ ";\u20DF;\u20E0;\u20E1" // symbol accents
+ ",'\u002D';\u00AD" // dashes
+ ";\u2010;\u2011;\u2012" // dashes
+ ";\u2013;\u2014;\u2015" // dashes
+ ";\u2212" // dashes
// other punctuation
+ "<'\u005f'" // underline/underscore (spacing)
+ "<\u00af" // overline or macron (spacing)
+ "<'\u002c'" // comma (spacing)
+ "<'\u003b'" // semicolon
+ "<'\u003a'" // colon
+ "<'\u0021'" // exclamation point
+ "<\u00a1" // inverted exclamation point
+ "<'\u003f'" // question mark
+ "<\u00bf" // inverted question mark
+ "<'\u002f'" // slash
+ "<'\u002e'" // period/full stop
+ "<\u00b4" // acute accent (spacing)
+ "<'\u0060'" // grave accent (spacing)
+ "<'\u005e'" // circumflex accent (spacing)
+ "<\u00a8" // diaresis/umlaut accent (spacing)
+ "<'\u007e'" // tilde accent (spacing)
+ "<\u00b7" // middle dot (spacing)
+ "<\u00b8" // cedilla accent (spacing)
+ "<'\u0027'" // apostrophe
+ "<'\"'" // quotation marks
+ "<\u00ab" // left angle quotes
+ "<\u00bb" // right angle quotes
+ "<'\u0028'" // left parenthesis
+ "<'\u0029'" // right parenthesis
+ "<'\u005b'" // left bracket
+ "<'\u005d'" // right bracket
+ "<'\u007b'" // left brace
+ "<'\u007d'" // right brace
+ "<\u00a7" // section symbol
+ "<\u00b6" // paragraph symbol
+ "<\u00a9" // copyright symbol
+ "<\u00ae" // registered trademark symbol
+ "<'\u0040'" // at sign
+ "<\u00a4" // international currency symbol
+ "<\u0e3f" // baht sign
+ "<\u00a2" // cent sign
+ "<\u20a1" // colon sign
+ "<\u20a2" // cruzeiro sign
+ "<'\u0024'" // dollar sign
+ "<\u20ab" // dong sign
+ "<\u20ac" // euro sign
+ "<\u20a3" // franc sign
+ "<\u20a4" // lira sign
+ "<\u20a5" // mill sign
+ "<\u20a6" // naira sign
+ "<\u20a7" // peseta sign
+ "<\u00a3" // pound-sterling sign
+ "<\u20a8" // rupee sign
+ "<\u20aa" // new shekel sign
+ "<\u20a9" // won sign
+ "<\u00a5" // yen sign
+ "<'\u002a'" // asterisk
+ "<'\\'" // backslash
+ "<'\u0026'" // ampersand
+ "<'\u0023'" // number sign
+ "<'\u0025'" // percent sign
+ "<'\u002b'" // plus sign
+ "<\u00b1" // plus-or-minus sign
+ "<\u00f7" // divide sign
+ "<\u00d7" // multiply sign
+ "<'\u003c'" // less-than sign
+ "<'\u003d'" // equal sign
+ "<'\u003e'" // greater-than sign
+ "<\u00ac" // end of line symbol/logical NOT symbol
+ "<'\u007c'" // vertical line/logical OR symbol
+ "<\u00a6" // broken vertical line
+ "<\u00b0" // degree symbol
+ "<\u00b5" // micro symbol
// NUMERICS
+ "<0<1<2<3<4<5<6<7<8<9"
+ "<\u00bc<\u00bd<\u00be" // 1/4,1/2,3/4 fractions
// NON-IGNORABLES
+ "<a,A"
+ "<b,B"
+ "<c,C"
+ "<d,D"
+ "<\u00F0,\u00D0" // eth
+ "<e,E"
+ "<f,F"
+ "<g,G"
+ "<h,H"
+ "<i,I"
+ "<j,J"
+ "<k,K"
+ "<l,L"
+ "<m,M"
+ "<n,N"
+ "<o,O"
+ "<p,P"
+ "<q,Q"
+ "<r,R"
+ "<s, S & SS,\u00DF" // s-zet
+ "<t,T"
+ "& TH, \u00DE &TH, \u00FE " // thorn
+ "<u,U"
+ "<v,V"
+ "<w,W"
+ "<x,X"
+ "<y,Y"
+ "<z,Z"
+ "&AE,\u00C6" // ae & AE ligature
+ "&AE,\u00E6"
+ "&OE,\u0152" // oe & OE ligature
+ "&OE,\u0153";
// No instantiation
private CollationRules() {
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*/
package sun.util.locale.provider;
import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.text.spi.CollatorProvider;
import java.util.Locale;
import java.util.Set;
/**
* Concrete implementation of the
* {@link java.text.spi.CollatorProvider CollatorProvider} class
* for the JRE LocaleProviderAdapter.
*/
public class CollatorProviderImpl extends CollatorProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public CollatorProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a new <code>Collator</code> instance for the specified locale.
* @param locale the desired locale.
* @return the <code>Collator</code> for the desired locale.
* @exception NullPointerException if
* <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.text.Collator#getInstance(java.util.Locale)
*/
@Override
public Collator getInstance(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
Collator result = null;
// Load the resource of the desired locale from resource
// manager.
String colString = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCollationData();
try
{
result = new RuleBasedCollator(CollationRules.DEFAULTRULES +
colString);
}
catch(ParseException foo)
{
// predefined tables should contain correct grammar
try {
result = new RuleBasedCollator(CollationRules.DEFAULTRULES);
} catch (ParseException bar) {
// the default rules should always be parsable.
throw new InternalError(bar);
}
}
// Now that RuleBasedCollator adds expansions for pre-composed characters
// into their decomposed equivalents, the default collators don't need
// to have decomposition turned on. Laura, 5/5/98, bug 4114077
result.setDecomposition(Collator.NO_DECOMPOSITION);
return (Collator)result.clone();
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Locale;
import java.util.Set;
import java.util.spi.CurrencyNameProvider;
/**
* Concrete implementation of the
* {@link java.util.spi.CurrencyNameProvider CurrencyNameProvider} class
* for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class CurrencyNameProviderImpl extends CurrencyNameProvider
implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public CurrencyNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
/**
* Gets the symbol of the given currency code for the specified locale.
* For example, for "USD" (US Dollar), the symbol is "$" if the specified
* locale is the US, while for other locales it may be "US$". If no
* symbol can be determined, null should be returned.
*
* @param currencyCode the ISO 4217 currency code, which
* consists of three upper-case letters between 'A' (U+0041) and
* 'Z' (U+005A)
* @param locale the desired locale
* @return the symbol of the given currency code for the specified locale, or null if
* the symbol is not available for the locale
* @exception NullPointerException if <code>currencyCode</code> or
* <code>locale</code> is null
* @exception IllegalArgumentException if <code>currencyCode</code> is not in
* the form of three upper-case letters, or <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.util.Currency#getSymbol(java.util.Locale)
*/
@Override
public String getSymbol(String currencyCode, Locale locale) {
return getString(currencyCode.toUpperCase(Locale.ROOT), locale);
}
/**
* Returns a name for the currency that is appropriate for display to the
* user. The default implementation returns null.
*
* @param currencyCode the ISO 4217 currency code, which
* consists of three upper-case letters between 'A' (U+0041) and
* 'Z' (U+005A)
* @param locale the desired locale
* @return the name for the currency that is appropriate for display to the
* user, or null if the name is not available for the locale
* @exception IllegalArgumentException if <code>currencyCode</code> is not in
* the form of three upper-case letters, or <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @exception NullPointerException if <code>currencyCode</code> or
* <code>locale</code> is <code>null</code>
* @since 1.7
*/
@Override
public String getDisplayName(String currencyCode, Locale locale) {
return getString(currencyCode.toLowerCase(Locale.ROOT), locale);
}
private String getString(String key, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCurrencyName(key);
}
}

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.spi.DateFormatProvider;
import java.util.Calendar;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;
/**
* Concrete implementation of the {@link java.text.spi.DateFormatProvider
* DateFormatProvider} class for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class DateFormatProviderImpl extends DateFormatProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public DateFormatProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a new <code>DateFormat</code> instance which formats time
* with the given formatting style for the specified locale.
* @param style the given formatting style. Either one of
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
* @param locale the desired locale.
* @exception IllegalArgumentException if <code>style</code> is invalid,
* or if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @exception NullPointerException if <code>locale</code> is null
* @return a time formatter.
* @see java.text.DateFormat#getTimeInstance(int, java.util.Locale)
*/
@Override
public DateFormat getTimeInstance(int style, Locale locale) {
return getInstance(-1, style, locale);
}
/**
* Returns a new <code>DateFormat</code> instance which formats date
* with the given formatting style for the specified locale.
* @param style the given formatting style. Either one of
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
* @param locale the desired locale.
* @exception IllegalArgumentException if <code>style</code> is invalid,
* or if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @exception NullPointerException if <code>locale</code> is null
* @return a date formatter.
* @see java.text.DateFormat#getDateInstance(int, java.util.Locale)
*/
@Override
public DateFormat getDateInstance(int style, Locale locale) {
return getInstance(style, -1, locale);
}
/**
* Returns a new <code>DateFormat</code> instance which formats date and time
* with the given formatting style for the specified locale.
* @param dateStyle the given date formatting style. Either one of
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
* @param timeStyle the given time formatting style. Either one of
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
* @param locale the desired locale.
* @exception IllegalArgumentException if <code>dateStyle</code> or
* <code>timeStyle</code> is invalid,
* or if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @exception NullPointerException if <code>locale</code> is null
* @return a date/time formatter.
* @see java.text.DateFormat#getDateTimeInstance(int, int, java.util.Locale)
*/
@Override
public DateFormat getDateTimeInstance(int dateStyle, int timeStyle,
Locale locale) {
return getInstance(dateStyle, timeStyle, locale);
}
private DateFormat getInstance(int dateStyle, int timeStyle, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
SimpleDateFormat sdf = new SimpleDateFormat("", locale);
Calendar cal = sdf.getCalendar();
try {
String pattern = LocaleProviderAdapter.forType(type)
.getLocaleResources(locale).getDateTimePattern(timeStyle, dateStyle,
cal);
sdf.applyPattern(pattern);
} catch (MissingResourceException mre) {
// Specify the fallback pattern
sdf.applyPattern("M/d/yy h:mm a");
}
return sdf;
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.text.DateFormatSymbols;
import java.text.spi.DateFormatSymbolsProvider;
import java.util.Locale;
import java.util.Set;
/**
* Concrete implementation of the {@link java.text.spi.DateFormatSymbolsProvider
* DateFormatSymbolsProvider} class for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class DateFormatSymbolsProviderImpl extends DateFormatSymbolsProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public DateFormatSymbolsProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a new <code>DateFormatSymbols</code> instance for the
* specified locale.
*
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a <code>DateFormatSymbols</code> instance.
* @see java.text.DateFormatSymbols#getInstance(java.util.Locale)
*/
@Override
public DateFormatSymbols getInstance(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
return new DateFormatSymbols(locale);
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.text.DecimalFormatSymbols;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.util.Locale;
import java.util.Set;
/**
* Concrete implementation of the {@link java.text.spi.DecimalFormatSymbolsProvider
* DecimalFormatSymbolsProvider} class for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class DecimalFormatSymbolsProviderImpl extends DecimalFormatSymbolsProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public DecimalFormatSymbolsProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a new <code>DecimalFormatSymbols</code> instance for the
* specified locale.
*
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a <code>DecimalFormatSymbols</code> instance.
* @see java.text.DecimalFormatSymbols#getInstance(java.util.Locale)
*/
@Override
public DecimalFormatSymbols getInstance(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
return new DecimalFormatSymbols(locale);
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
/**
* FallbackProviderAdapter implementation.
*
* @author Naoto Sato
*/
public class FallbackLocaleProviderAdapter extends JRELocaleProviderAdapter {
/**
* Supported language tag set.
*/
private static final Set<String> rootTagSet =
Collections.singleton(Locale.ROOT.toLanguageTag());
/**
* Fallback provider only provides the ROOT locale data.
*/
private final LocaleResources rootLocaleResources =
new LocaleResources(this, Locale.ROOT);
/**
* Returns the type of this LocaleProviderAdapter
*/
@Override
public LocaleProviderAdapter.Type getAdapterType() {
return Type.FALLBACK;
}
@Override
public LocaleResources getLocaleResources(Locale locale) {
return rootLocaleResources;
}
@Override
protected Set<String> createLanguageTagSet(String category) {
return rootTagSet;
}
@Override
public boolean isSupportedProviderLocale(Locale locale, Set<String>langtags) {
return Locale.ROOT.equals(locale);
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.spi.LocaleServiceProvider;
/**
* LocaleProviderAdapter implementation for the host locale data.
* Currently it is only implemented on Windows Vista or later.
*
* @author Naoto Sato
*/
public class HostLocaleProviderAdapter extends AuxLocaleProviderAdapter {
/**
* Returns the type of this LocaleProviderAdapter
*/
@Override
public LocaleProviderAdapter.Type getAdapterType() {
return LocaleProviderAdapter.Type.HOST;
}
@Override
@SuppressWarnings("unchecked")
protected <P extends LocaleServiceProvider> P findInstalledProvider(final Class<P> c) {
try {
Method getter = HostLocaleProviderAdapterImpl.class.getMethod(
"get" + c.getSimpleName(), (Class<?>[]) null);
return (P)getter.invoke(null, (Object[]) null);
} catch (NoSuchMethodException |
IllegalAccessException |
IllegalArgumentException |
InvocationTargetException ex) {
LocaleServiceProviderPool.config(HostLocaleProviderAdapter.class, ex.toString());
}
return null;
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Locale;
/**
* Singletons for the well-known JRE-specific Locales. (th_TH isn't JRE specific,
* but it's treated as a special Locale because of the Thai Buddhist calendar
* support.)
*
* @author Masayoshi Okutsu
*/
public class JRELocaleConstants {
public static final Locale JA_JP_JP = new Locale("ja", "JP", "JP");
public static final Locale NO_NO_NY = new Locale("no", "NO", "NY");
public static final Locale TH_TH = new Locale("th", "TH");
public static final Locale TH_TH_TH = new Locale("th", "TH", "TH");
private JRELocaleConstants() {
}
}

View file

@ -0,0 +1,548 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.text.spi.DateFormatProvider;
import java.text.spi.DateFormatSymbolsProvider;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.text.spi.NumberFormatProvider;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import java.util.spi.LocaleServiceProvider;
import java.util.spi.TimeZoneNameProvider;
import sun.text.spi.JavaTimeDateTimePatternProvider;
import sun.util.resources.LocaleData;
import sun.util.spi.CalendarProvider;
/**
* LocaleProviderAdapter implementation for the legacy JRE locale data.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter {
private final ConcurrentMap<String, Set<String>> langtagSets
= new ConcurrentHashMap<>();
private final ConcurrentMap<Locale, LocaleResources> localeResourcesMap
= new ConcurrentHashMap<>();
// LocaleData specific to this LocaleProviderAdapter.
private volatile LocaleData localeData;
/**
* Returns the type of this LocaleProviderAdapter
*/
@Override
public LocaleProviderAdapter.Type getAdapterType() {
return Type.JRE;
}
/**
* Getter method for Locale Service Providers
*/
@Override
@SuppressWarnings("unchecked")
public <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c) {
switch (c.getSimpleName()) {
case "BreakIteratorProvider":
return (P) getBreakIteratorProvider();
case "CollatorProvider":
return (P) getCollatorProvider();
case "DateFormatProvider":
return (P) getDateFormatProvider();
case "DateFormatSymbolsProvider":
return (P) getDateFormatSymbolsProvider();
case "DecimalFormatSymbolsProvider":
return (P) getDecimalFormatSymbolsProvider();
case "NumberFormatProvider":
return (P) getNumberFormatProvider();
case "CurrencyNameProvider":
return (P) getCurrencyNameProvider();
case "LocaleNameProvider":
return (P) getLocaleNameProvider();
case "TimeZoneNameProvider":
return (P) getTimeZoneNameProvider();
case "CalendarDataProvider":
return (P) getCalendarDataProvider();
case "CalendarNameProvider":
return (P) getCalendarNameProvider();
case "CalendarProvider":
return (P) getCalendarProvider();
case "JavaTimeDateTimePatternProvider":
return (P) getJavaTimeDateTimePatternProvider();
default:
throw new InternalError("should not come down here");
}
}
private volatile BreakIteratorProvider breakIteratorProvider;
private volatile CollatorProvider collatorProvider;
private volatile DateFormatProvider dateFormatProvider;
private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider;
private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider;
private volatile NumberFormatProvider numberFormatProvider;
private volatile CurrencyNameProvider currencyNameProvider;
private volatile LocaleNameProvider localeNameProvider;
private volatile TimeZoneNameProvider timeZoneNameProvider;
private volatile CalendarDataProvider calendarDataProvider;
private volatile CalendarNameProvider calendarNameProvider;
private volatile CalendarProvider calendarProvider;
private volatile JavaTimeDateTimePatternProvider javaTimeDateTimePatternProvider;
/*
* Getter methods for java.text.spi.* providers
*/
@Override
public BreakIteratorProvider getBreakIteratorProvider() {
if (breakIteratorProvider == null) {
BreakIteratorProvider provider = AccessController.doPrivileged(
(PrivilegedAction<BreakIteratorProvider>) () ->
new BreakIteratorProviderImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (breakIteratorProvider == null) {
breakIteratorProvider = provider;
}
}
}
return breakIteratorProvider;
}
@Override
public CollatorProvider getCollatorProvider() {
if (collatorProvider == null) {
CollatorProvider provider = AccessController.doPrivileged(
(PrivilegedAction<CollatorProvider>) () ->
new CollatorProviderImpl(
getAdapterType(),
getLanguageTagSet("CollationData")));
synchronized (this) {
if (collatorProvider == null) {
collatorProvider = provider;
}
}
}
return collatorProvider;
}
@Override
public DateFormatProvider getDateFormatProvider() {
if (dateFormatProvider == null) {
DateFormatProvider provider = AccessController.doPrivileged(
(PrivilegedAction<DateFormatProvider>) () ->
new DateFormatProviderImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (dateFormatProvider == null) {
dateFormatProvider = provider;
}
}
}
return dateFormatProvider;
}
@Override
public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
if (dateFormatSymbolsProvider == null) {
DateFormatSymbolsProvider provider = AccessController.doPrivileged(
(PrivilegedAction<DateFormatSymbolsProvider>) () ->
new DateFormatSymbolsProviderImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (dateFormatSymbolsProvider == null) {
dateFormatSymbolsProvider = provider;
}
}
}
return dateFormatSymbolsProvider;
}
@Override
public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
if (decimalFormatSymbolsProvider == null) {
DecimalFormatSymbolsProvider provider = AccessController.doPrivileged(
(PrivilegedAction<DecimalFormatSymbolsProvider>) () ->
new DecimalFormatSymbolsProviderImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (decimalFormatSymbolsProvider == null) {
decimalFormatSymbolsProvider = provider;
}
}
}
return decimalFormatSymbolsProvider;
}
@Override
public NumberFormatProvider getNumberFormatProvider() {
if (numberFormatProvider == null) {
NumberFormatProvider provider = AccessController.doPrivileged(
(PrivilegedAction<NumberFormatProvider>) () ->
new NumberFormatProviderImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (numberFormatProvider == null) {
numberFormatProvider = provider;
}
}
}
return numberFormatProvider;
}
/**
* Getter methods for java.util.spi.* providers
*/
@Override
public CurrencyNameProvider getCurrencyNameProvider() {
if (currencyNameProvider == null) {
CurrencyNameProvider provider = AccessController.doPrivileged(
(PrivilegedAction<CurrencyNameProvider>) () ->
new CurrencyNameProviderImpl(
getAdapterType(),
getLanguageTagSet("CurrencyNames")));
synchronized (this) {
if (currencyNameProvider == null) {
currencyNameProvider = provider;
}
}
}
return currencyNameProvider;
}
@Override
public LocaleNameProvider getLocaleNameProvider() {
if (localeNameProvider == null) {
LocaleNameProvider provider = AccessController.doPrivileged(
(PrivilegedAction<LocaleNameProvider>) () ->
new LocaleNameProviderImpl(
getAdapterType(),
getLanguageTagSet("LocaleNames")));
synchronized (this) {
if (localeNameProvider == null) {
localeNameProvider = provider;
}
}
}
return localeNameProvider;
}
@Override
public TimeZoneNameProvider getTimeZoneNameProvider() {
if (timeZoneNameProvider == null) {
TimeZoneNameProvider provider = AccessController.doPrivileged(
(PrivilegedAction<TimeZoneNameProvider>) () ->
new TimeZoneNameProviderImpl(
getAdapterType(),
getLanguageTagSet("TimeZoneNames")));
synchronized (this) {
if (timeZoneNameProvider == null) {
timeZoneNameProvider = provider;
}
}
}
return timeZoneNameProvider;
}
@Override
public CalendarDataProvider getCalendarDataProvider() {
if (calendarDataProvider == null) {
CalendarDataProvider provider = AccessController.doPrivileged(
(PrivilegedAction<CalendarDataProvider>) () ->
new CalendarDataProviderImpl(
getAdapterType(),
getLanguageTagSet("CalendarData")));
synchronized (this) {
if (calendarDataProvider == null) {
calendarDataProvider = provider;
}
}
}
return calendarDataProvider;
}
@Override
public CalendarNameProvider getCalendarNameProvider() {
if (calendarNameProvider == null) {
CalendarNameProvider provider = AccessController.doPrivileged(
(PrivilegedAction<CalendarNameProvider>) () ->
new CalendarNameProviderImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (calendarNameProvider == null) {
calendarNameProvider = provider;
}
}
}
return calendarNameProvider;
}
/**
* Getter methods for sun.util.spi.* providers
*/
@Override
public CalendarProvider getCalendarProvider() {
if (calendarProvider == null) {
CalendarProvider provider = AccessController.doPrivileged(
(PrivilegedAction<CalendarProvider>) () ->
new CalendarProviderImpl(
getAdapterType(),
getLanguageTagSet("CalendarData")));
synchronized (this) {
if (calendarProvider == null) {
calendarProvider = provider;
}
}
}
return calendarProvider;
}
/**
* Getter methods for sun.text.spi.JavaTimeDateTimePatternProvider provider
*/
@Override
public JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
if (javaTimeDateTimePatternProvider == null) {
JavaTimeDateTimePatternProvider provider = AccessController.doPrivileged(
(PrivilegedAction<JavaTimeDateTimePatternProvider>) ()
-> new JavaTimeDateTimePatternImpl(
getAdapterType(),
getLanguageTagSet("FormatData")));
synchronized (this) {
if (javaTimeDateTimePatternProvider == null) {
javaTimeDateTimePatternProvider = provider;
}
}
}
return javaTimeDateTimePatternProvider;
}
@Override
public LocaleResources getLocaleResources(Locale locale) {
LocaleResources lr = localeResourcesMap.get(locale);
if (lr == null) {
lr = new LocaleResources(this, locale);
LocaleResources lrc = localeResourcesMap.putIfAbsent(locale, lr);
if (lrc != null) {
lr = lrc;
}
}
return lr;
}
// ResourceBundleBasedAdapter method implementation
@Override
public LocaleData getLocaleData() {
if (localeData == null) {
synchronized (this) {
if (localeData == null) {
localeData = new LocaleData(getAdapterType());
}
}
}
return localeData;
}
@Override
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
return ResourceBundle.Control
.getNoFallbackControl(ResourceBundle.Control.FORMAT_DEFAULT)
.getCandidateLocales(baseName, locale);
}
/**
* Returns a list of the installed locales. Currently, this simply returns
* the list of locales for which a sun.text.resources.FormatData bundle
* exists. This bundle family happens to be the one with the broadest
* locale coverage in the JRE.
*/
@Override
public Locale[] getAvailableLocales() {
return AvailableJRELocales.localeList.clone();
}
public Set<String> getLanguageTagSet(String category) {
Set<String> tagset = langtagSets.get(category);
if (tagset == null) {
tagset = createLanguageTagSet(category);
Set<String> ts = langtagSets.putIfAbsent(category, tagset);
if (ts != null) {
tagset = ts;
}
}
return tagset;
}
protected Set<String> createLanguageTagSet(String category) {
String supportedLocaleString = createSupportedLocaleString(category);
if (supportedLocaleString == null) {
return Collections.emptySet();
}
Set<String> tagset = new HashSet<>();
StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
while (tokens.hasMoreTokens()) {
tagset.add(tokens.nextToken());
}
return tagset;
}
private static String createSupportedLocaleString(String category) {
// Directly call Base tags, as we know it's in the base module.
String supportedLocaleString = BaseLocaleDataMetaInfo.getSupportedLocaleString(category);
// Use ServiceLoader to dynamically acquire installed locales' tags.
try {
String nonBaseTags = AccessController.doPrivileged((PrivilegedExceptionAction<String>) () -> {
StringBuilder tags = new StringBuilder();
for (LocaleDataMetaInfo ldmi :
ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
String t = ldmi.availableLanguageTags(category);
if (t != null) {
if (tags.length() > 0) {
tags.append(' ');
}
tags.append(t);
}
}
}
return tags.toString();
});
if (nonBaseTags != null) {
supportedLocaleString += " " + nonBaseTags;
}
} catch (Exception e) {
// catch any exception, and ignore them as if non-EN locales do not exist.
}
return supportedLocaleString;
}
/**
* Lazy load available locales.
*/
private static class AvailableJRELocales {
private static final Locale[] localeList = createAvailableLocales();
private AvailableJRELocales() {
}
}
private static Locale[] createAvailableLocales() {
/*
* Gets the locale string list from LocaleDataMetaInfo classes and then
* contructs the Locale array and a set of language tags based on the
* locale string returned above.
*/
String supportedLocaleString = createSupportedLocaleString("AvailableLocales");
if (supportedLocaleString.length() == 0) {
throw new InternalError("No available locales for JRE");
}
StringTokenizer localeStringTokenizer = new StringTokenizer(supportedLocaleString);
int length = localeStringTokenizer.countTokens();
Locale[] locales = new Locale[length + 1];
locales[0] = Locale.ROOT;
for (int i = 1; i <= length; i++) {
String currentToken = localeStringTokenizer.nextToken();
switch (currentToken) {
case "ja-JP-JP":
locales[i] = JRELocaleConstants.JA_JP_JP;
break;
case "no-NO-NY":
locales[i] = JRELocaleConstants.NO_NO_NY;
break;
case "th-TH-TH":
locales[i] = JRELocaleConstants.TH_TH_TH;
break;
default:
locales[i] = Locale.forLanguageTag(currentToken);
}
}
return locales;
}
@Override
public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) {
if (Locale.ROOT.equals(locale)) {
return true;
}
locale = locale.stripExtensions();
if (langtags.contains(locale.toLanguageTag())) {
return true;
}
String oldname = locale.toString().replace('_', '-');
return langtags.contains(oldname) ||
"ja-JP-JP".equals(oldname) ||
"th-TH-TH".equals(oldname) ||
"no-NO-NY".equals(oldname);
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Locale;
import java.util.Set;
import sun.text.spi.JavaTimeDateTimePatternProvider;
/**
* Concrete implementation of the {@link sun.text.spi.JavaTimeDateTimePatternProvider
* } class for the JRE LocaleProviderAdapter.
*
*/
public class JavaTimeDateTimePatternImpl extends JavaTimeDateTimePatternProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public JavaTimeDateTimePatternImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
@Override
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale);
String pattern = lr.getJavaTimeDateTimePattern(
timeStyle, dateStyle, calType);
return pattern;
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#warn This file is preprocessed before being compiled
/*
* This class contains a map which records the locale list string for
* each resource in sun.util.resources & sun.text.resources.
* It is used to avoid loading non-existent localized resources so that
* jar files won't be opened unnecessary to look up them.
*/
package #Package#;
import java.util.HashMap;
import java.util.Map;
import sun.util.locale.provider.LocaleDataMetaInfo;
import static sun.util.locale.provider.LocaleProviderAdapter.Type;
public class #Lang#LocaleDataMetaInfo implements LocaleDataMetaInfo {
private static final Map<String, String> resourceNameToLocales = new HashMap<>(9);
static {
/* During JDK build time, #XXX_YYY# will be replaced by a string contain all the locales
supported by the resource.
Don't remove the space character between " and #. That is put there purposely so that
look up locale string such as "en" could be based on if it contains " en ".
*/
resourceNameToLocales.put("FormatData",
" #FormatData_Locales# ");
resourceNameToLocales.put("CollationData",
" #CollationData_Locales# ");
resourceNameToLocales.put("BreakIteratorInfo",
" #BreakIteratorInfo_Locales# ");
resourceNameToLocales.put("BreakIteratorRules",
" #BreakIteratorRules_Locales# ");
resourceNameToLocales.put("TimeZoneNames",
" #TimeZoneNames_Locales# ");
resourceNameToLocales.put("LocaleNames",
" #LocaleNames_Locales# ");
resourceNameToLocales.put("CurrencyNames",
" #CurrencyNames_Locales# ");
resourceNameToLocales.put("CalendarData",
" #CalendarData_Locales# ");
resourceNameToLocales.put("AvailableLocales",
" #AvailableLocales_Locales# ");
}
/*
* Gets the supported locales string based on the availability of
* locale data resource bundles for each resource name.
*
* @param resourceName the resource name
* @return the supported locale string for the passed in resource.
*/
public static String getSupportedLocaleString(String resourceName) {
return resourceNameToLocales.getOrDefault(resourceName, "");
}
@Override
public Type getType() {
return Type.JRE;
}
@Override
public String availableLanguageTags(String category) {
return getSupportedLocaleString(category);
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
/**
* LocaleData meta info SPI
*
* @author Naoto Sato
*/
public interface LocaleDataMetaInfo {
/**
* Returns the type of LocaleProviderAdapter for which this LocaleData
* provides the data.
* @return type The type of the adapter.
*/
public LocaleProviderAdapter.Type getType();
/**
* Returns the string concatenation of the supported language tags in
* this LocaleData instance
* @param category category of the locale data.
* @return concatenated language tags, separated by a space.
*/
public String availableLanguageTags(String category);
}

View file

@ -0,0 +1,183 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Locale;
import java.util.Set;
import java.util.spi.LocaleNameProvider;
/**
* Concrete implementation of the
* {@link java.util.spi.LocaleNameProvider LocaleNameProvider} class
* for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class LocaleNameProviderImpl extends LocaleNameProvider implements AvailableLanguageTags {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public LocaleNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a localized name for the given ISO 639 language code and the
* given locale that is appropriate for display to the user.
* For example, if <code>languageCode</code> is "fr" and <code>locale</code>
* is en_US, getDisplayLanguage() will return "French"; if <code>languageCode</code>
* is "en" and <code>locale</code> is fr_FR, getDisplayLanguage() will return "anglais".
* If the name returned cannot be localized according to <code>locale</code>,
* (say, the provider does not have a Japanese name for Croatian),
* this method returns null.
* @param lang the ISO 639 language code string in the form of two
* lower-case letters between 'a' (U+0061) and 'z' (U+007A)
* @param locale the desired locale
* @return the name of the given language code for the specified locale, or null if it's not
* available.
* @exception NullPointerException if <code>languageCode</code> or <code>locale</code> is null
* @exception IllegalArgumentException if <code>languageCode</code> is not in the form of
* two lower-case letters, or <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.util.Locale#getDisplayLanguage(java.util.Locale)
*/
@Override
public String getDisplayLanguage(String lang, Locale locale) {
return getDisplayString(lang, locale);
}
/**
* Returns a localized name for the given <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
* IETF BCP47</a> script code and the given locale that is appropriate for
* display to the user.
* For example, if <code>scriptCode</code> is "Latn" and <code>locale</code>
* is en_US, getDisplayScript() will return "Latin"; if <code>scriptCode</code>
* is "Cyrl" and <code>locale</code> is fr_FR, getDisplayScript() will return "cyrillique".
* If the name returned cannot be localized according to <code>locale</code>,
* (say, the provider does not have a Japanese name for Cyrillic),
* this method returns null. The default implementation returns null.
* @param scriptCode the four letter script code string in the form of title-case
* letters (the first letter is upper-case character between 'A' (U+0041) and
* 'Z' (U+005A) followed by three lower-case character between 'a' (U+0061)
* and 'z' (U+007A)).
* @param locale the desired locale
* @return the name of the given script code for the specified locale, or null if it's not
* available.
* @exception NullPointerException if <code>scriptCode</code> or <code>locale</code> is null
* @exception IllegalArgumentException if <code>scriptCode</code> is not in the form of
* four title case letters, or <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.util.Locale#getDisplayScript(java.util.Locale)
*/
@Override
public String getDisplayScript(String scriptCode, Locale locale) {
return getDisplayString(scriptCode, locale);
}
/**
* Returns a localized name for the given ISO 3166 country code and the
* given locale that is appropriate for display to the user.
* For example, if <code>countryCode</code> is "FR" and <code>locale</code>
* is en_US, getDisplayCountry() will return "France"; if <code>countryCode</code>
* is "US" and <code>locale</code> is fr_FR, getDisplayCountry() will return "Etats-Unis".
* If the name returned cannot be localized according to <code>locale</code>,
* (say, the provider does not have a Japanese name for Croatia),
* this method returns null.
* @param ctry the ISO 3166 country code string in the form of two
* upper-case letters between 'A' (U+0041) and 'Z' (U+005A)
* @param locale the desired locale
* @return the name of the given country code for the specified locale, or null if it's not
* available.
* @exception NullPointerException if <code>countryCode</code> or <code>locale</code> is null
* @exception IllegalArgumentException if <code>countryCode</code> is not in the form of
* two upper-case letters, or <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.util.Locale#getDisplayCountry(java.util.Locale)
*/
@Override
public String getDisplayCountry(String ctry, Locale locale) {
return getDisplayString(ctry, locale);
}
/**
* Returns a localized name for the given variant code and the given locale that
* is appropriate for display to the user.
* If the name returned cannot be localized according to <code>locale</code>,
* this method returns null.
* @param vrnt the variant string
* @param locale the desired locale
* @return the name of the given variant string for the specified locale, or null if it's not
* available.
* @exception NullPointerException if <code>variant</code> or <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @see java.util.Locale#getDisplayVariant(java.util.Locale)
*/
@Override
public String getDisplayVariant(String vrnt, Locale locale) {
return getDisplayString("%%"+vrnt, locale);
}
private String getDisplayString(String key, Locale locale) {
if (key == null || locale == null) {
throw new NullPointerException();
}
return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getLocaleName(key);
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,453 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.text.spi.DateFormatProvider;
import java.text.spi.DateFormatSymbolsProvider;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.text.spi.NumberFormatProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import java.util.spi.LocaleServiceProvider;
import java.util.spi.TimeZoneNameProvider;
import sun.security.action.GetPropertyAction;
import sun.text.spi.JavaTimeDateTimePatternProvider;
import sun.util.spi.CalendarProvider;
/**
* The LocaleProviderAdapter abstract class.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public abstract class LocaleProviderAdapter {
/**
* Adapter type.
*/
public static enum Type {
JRE("sun.util.locale.provider.JRELocaleProviderAdapter", "sun.util.resources", "sun.text.resources"),
CLDR("sun.util.cldr.CLDRLocaleProviderAdapter", "sun.util.resources.cldr", "sun.text.resources.cldr"),
SPI("sun.util.locale.provider.SPILocaleProviderAdapter"),
HOST("sun.util.locale.provider.HostLocaleProviderAdapter"),
FALLBACK("sun.util.locale.provider.FallbackLocaleProviderAdapter", "sun.util.resources", "sun.text.resources");
private final String CLASSNAME;
private final String UTIL_RESOURCES_PACKAGE;
private final String TEXT_RESOURCES_PACKAGE;
private Type(String className) {
this(className, null, null);
}
private Type(String className, String util, String text) {
CLASSNAME = className;
UTIL_RESOURCES_PACKAGE = util;
TEXT_RESOURCES_PACKAGE = text;
}
public String getAdapterClassName() {
return CLASSNAME;
}
public String getUtilResourcesPackage() {
return UTIL_RESOURCES_PACKAGE;
}
public String getTextResourcesPackage() {
return TEXT_RESOURCES_PACKAGE;
}
}
/**
* LocaleProviderAdapter preference list.
*/
private static final List<Type> adapterPreference;
/**
* LocaleProviderAdapter instances
*/
private static final Map<Type, LocaleProviderAdapter> adapterInstances = new ConcurrentHashMap<>();
/**
* Default fallback adapter type, which should return something meaningful in any case.
* This is either CLDR or FALLBACK.
*/
static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter;
/**
* Adapter lookup cache.
*/
private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>>
adapterCache = new ConcurrentHashMap<>();
static {
String order = GetPropertyAction.privilegedGetProperty("java.locale.providers");
List<Type> typeList = new ArrayList<>();
// Check user specified adapter preference
if (order != null && order.length() != 0) {
String[] types = order.split(",");
for (String type : types) {
type = type.trim().toUpperCase(Locale.ROOT);
if (type.equals("COMPAT")) {
type = "JRE";
}
try {
Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT));
if (!typeList.contains(aType)) {
typeList.add(aType);
}
} catch (IllegalArgumentException | UnsupportedOperationException e) {
// could be caused by the user specifying wrong
// provider name or format in the system property
LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString());
}
}
}
defaultLocaleProviderAdapter = Type.CLDR;
if (!typeList.isEmpty()) {
// bona fide preference exists
if (!(typeList.contains(Type.CLDR) || (typeList.contains(Type.JRE)))) {
// Append FALLBACK as the last resort when no ResourceBundleBasedAdapter is available.
typeList.add(Type.FALLBACK);
defaultLocaleProviderAdapter = Type.FALLBACK;
}
} else {
// Default preference list.
typeList.add(Type.CLDR);
typeList.add(Type.JRE);
}
adapterPreference = Collections.unmodifiableList(typeList);
}
/**
* Returns the singleton instance for each adapter type
*/
public static LocaleProviderAdapter forType(Type type) {
switch (type) {
case JRE:
case CLDR:
case SPI:
case HOST:
case FALLBACK:
LocaleProviderAdapter adapter = null;
LocaleProviderAdapter cached = adapterInstances.get(type);
if (cached == null) {
try {
// lazily load adapters here
@SuppressWarnings("deprecation")
Object tmp = Class.forName(type.getAdapterClassName()).newInstance();
adapter = (LocaleProviderAdapter)tmp;
cached = adapterInstances.putIfAbsent(type, adapter);
if (cached != null) {
adapter = cached;
}
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException |
UnsupportedOperationException e) {
LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString());
adapterInstances.putIfAbsent(type, NONEXISTENT_ADAPTER);
if (defaultLocaleProviderAdapter == type) {
defaultLocaleProviderAdapter = Type.FALLBACK;
}
}
} else if (cached != NONEXISTENT_ADAPTER) {
adapter = cached;
}
return adapter;
default:
throw new InternalError("unknown locale data adapter type");
}
}
public static LocaleProviderAdapter forJRE() {
return forType(Type.JRE);
}
public static LocaleProviderAdapter getResourceBundleBased() {
for (Type type : getAdapterPreference()) {
if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) {
LocaleProviderAdapter adapter = forType(type);
if (adapter != null) {
return adapter;
}
}
}
// Shouldn't happen.
throw new InternalError();
}
/**
* Returns the preference order of LocaleProviderAdapter.Type
*/
public static List<Type> getAdapterPreference() {
return adapterPreference;
}
/**
* Returns a LocaleProviderAdapter for the given locale service provider that
* best matches the given locale. This method returns the LocaleProviderAdapter
* for JRE if none is found for the given locale.
*
* @param providerClass the class for the locale service provider
* @param locale the desired locale.
* @return a LocaleProviderAdapter
*/
public static LocaleProviderAdapter getAdapter(Class<? extends LocaleServiceProvider> providerClass,
Locale locale) {
LocaleProviderAdapter adapter;
// cache lookup
ConcurrentMap<Locale, LocaleProviderAdapter> adapterMap = adapterCache.get(providerClass);
if (adapterMap != null) {
if ((adapter = adapterMap.get(locale)) != null) {
return adapter;
}
} else {
adapterMap = new ConcurrentHashMap<>();
adapterCache.putIfAbsent(providerClass, adapterMap);
}
// Fast look-up for the given locale
adapter = findAdapter(providerClass, locale);
if (adapter != null) {
adapterMap.putIfAbsent(locale, adapter);
return adapter;
}
// Try finding an adapter in the normal candidate locales path of the given locale.
List<Locale> lookupLocales = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT)
.getCandidateLocales("", locale);
for (Locale loc : lookupLocales) {
if (loc.equals(locale)) {
// We've already done with this loc.
continue;
}
adapter = findAdapter(providerClass, loc);
if (adapter != null) {
adapterMap.putIfAbsent(locale, adapter);
return adapter;
}
}
// returns the adapter for FALLBACK as the last resort
adapterMap.putIfAbsent(locale, forType(Type.FALLBACK));
return forType(Type.FALLBACK);
}
private static LocaleProviderAdapter findAdapter(Class<? extends LocaleServiceProvider> providerClass,
Locale locale) {
for (Type type : getAdapterPreference()) {
LocaleProviderAdapter adapter = forType(type);
if (adapter != null) {
LocaleServiceProvider provider = adapter.getLocaleServiceProvider(providerClass);
if (provider != null) {
if (provider.isSupportedLocale(locale)) {
return adapter;
}
}
}
}
return null;
}
/**
* A utility method for implementing the default LocaleServiceProvider.isSupportedLocale
* for the JRE, CLDR, and FALLBACK adapters.
*/
public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) {
LocaleProviderAdapter.Type type = getAdapterType();
assert type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK;
return false;
}
public static Locale[] toLocaleArray(Set<String> tags) {
Locale[] locs = new Locale[tags.size() + 1];
int index = 0;
locs[index++] = Locale.ROOT;
for (String tag : tags) {
switch (tag) {
case "ja-JP-JP":
locs[index++] = JRELocaleConstants.JA_JP_JP;
break;
case "th-TH-TH":
locs[index++] = JRELocaleConstants.TH_TH_TH;
break;
default:
locs[index++] = Locale.forLanguageTag(tag);
break;
}
}
return locs;
}
/**
* Returns the type of this LocaleProviderAdapter
*/
public abstract LocaleProviderAdapter.Type getAdapterType();
/**
* Getter method for Locale Service Providers.
*/
public abstract <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c);
/**
* Returns a BreakIteratorProvider for this LocaleProviderAdapter, or null if no
* BreakIteratorProvider is available.
*
* @return a BreakIteratorProvider
*/
public abstract BreakIteratorProvider getBreakIteratorProvider();
/**
* Returns a ollatorProvider for this LocaleProviderAdapter, or null if no
* ollatorProvider is available.
*
* @return a ollatorProvider
*/
public abstract CollatorProvider getCollatorProvider();
/**
* Returns a DateFormatProvider for this LocaleProviderAdapter, or null if no
* DateFormatProvider is available.
*
* @return a DateFormatProvider
*/
public abstract DateFormatProvider getDateFormatProvider();
/**
* Returns a DateFormatSymbolsProvider for this LocaleProviderAdapter, or null if no
* DateFormatSymbolsProvider is available.
*
* @return a DateFormatSymbolsProvider
*/
public abstract DateFormatSymbolsProvider getDateFormatSymbolsProvider();
/**
* Returns a DecimalFormatSymbolsProvider for this LocaleProviderAdapter, or null if no
* DecimalFormatSymbolsProvider is available.
*
* @return a DecimalFormatSymbolsProvider
*/
public abstract DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider();
/**
* Returns a NumberFormatProvider for this LocaleProviderAdapter, or null if no
* NumberFormatProvider is available.
*
* @return a NumberFormatProvider
*/
public abstract NumberFormatProvider getNumberFormatProvider();
/*
* Getter methods for java.util.spi.* providers
*/
/**
* Returns a CurrencyNameProvider for this LocaleProviderAdapter, or null if no
* CurrencyNameProvider is available.
*
* @return a CurrencyNameProvider
*/
public abstract CurrencyNameProvider getCurrencyNameProvider();
/**
* Returns a LocaleNameProvider for this LocaleProviderAdapter, or null if no
* LocaleNameProvider is available.
*
* @return a LocaleNameProvider
*/
public abstract LocaleNameProvider getLocaleNameProvider();
/**
* Returns a TimeZoneNameProvider for this LocaleProviderAdapter, or null if no
* TimeZoneNameProvider is available.
*
* @return a TimeZoneNameProvider
*/
public abstract TimeZoneNameProvider getTimeZoneNameProvider();
/**
* Returns a CalendarDataProvider for this LocaleProviderAdapter, or null if no
* CalendarDataProvider is available.
*
* @return a CalendarDataProvider
*/
public abstract CalendarDataProvider getCalendarDataProvider();
/**
* Returns a CalendarNameProvider for this LocaleProviderAdapter, or null if no
* CalendarNameProvider is available.
*
* @return a CalendarNameProvider
*/
public abstract CalendarNameProvider getCalendarNameProvider();
/**
* Returns a CalendarProvider for this LocaleProviderAdapter, or null if no
* CalendarProvider is available.
*
* @return a CalendarProvider
*/
public abstract CalendarProvider getCalendarProvider();
/**
* Returns a JavaTimeDateTimePatternProvider for this LocaleProviderAdapter,
* or null if no JavaTimeDateTimePatternProvider is available.
*
* @return a JavaTimeDateTimePatternProvider
*/
public abstract JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider();
public abstract LocaleResources getLocaleResources(Locale locale);
public abstract Locale[] getAvailableLocales();
private static final LocaleProviderAdapter NONEXISTENT_ADAPTER = new NonExistentAdapter();
private static final class NonExistentAdapter extends FallbackLocaleProviderAdapter {
@Override
public LocaleProviderAdapter.Type getAdapterType() {
return null;
}
private NonExistentAdapter() {};
}
}

View file

@ -0,0 +1,519 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.locale.provider;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.text.MessageFormat;
import java.util.Calendar;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import sun.util.calendar.ZoneInfo;
import sun.util.resources.LocaleData;
import sun.util.resources.OpenListResourceBundle;
import sun.util.resources.ParallelListResourceBundle;
import sun.util.resources.TimeZoneNamesBundle;
/**
* Central accessor to locale-dependent resources for JRE/CLDR provider adapters.
*
* @author Masayoshi Okutsu
* @author Naoto Sato
*/
public class LocaleResources {
private final Locale locale;
private final LocaleData localeData;
private final LocaleProviderAdapter.Type type;
// Resource cache
private final ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
private final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
// cache key prefixes
private static final String BREAK_ITERATOR_INFO = "BII.";
private static final String CALENDAR_DATA = "CALD.";
private static final String COLLATION_DATA_CACHEKEY = "COLD";
private static final String DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY = "DFSD";
private static final String CURRENCY_NAMES = "CN.";
private static final String LOCALE_NAMES = "LN.";
private static final String TIME_ZONE_NAMES = "TZN.";
private static final String ZONE_IDS_CACHEKEY = "ZID";
private static final String CALENDAR_NAMES = "CALN.";
private static final String NUMBER_PATTERNS_CACHEKEY = "NP";
private static final String DATE_TIME_PATTERN = "DTP.";
// null singleton cache value
private static final Object NULLOBJECT = new Object();
LocaleResources(ResourceBundleBasedAdapter adapter, Locale locale) {
this.locale = locale;
this.localeData = adapter.getLocaleData();
type = ((LocaleProviderAdapter)adapter).getAdapterType();
}
private void removeEmptyReferences() {
Object ref;
while ((ref = referenceQueue.poll()) != null) {
cache.remove(((ResourceReference)ref).getCacheKey());
}
}
Object getBreakIteratorInfo(String key) {
Object biInfo;
String cacheKey = BREAK_ITERATOR_INFO + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data == null || ((biInfo = data.get()) == null)) {
biInfo = localeData.getBreakIteratorInfo(locale).getObject(key);
cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue));
}
return biInfo;
}
@SuppressWarnings("unchecked")
byte[] getBreakIteratorResources(String key) {
return (byte[]) localeData.getBreakIteratorResources(locale).getObject(key);
}
int getCalendarData(String key) {
Integer caldata;
String cacheKey = CALENDAR_DATA + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data == null || ((caldata = (Integer) data.get()) == null)) {
ResourceBundle rb = localeData.getCalendarData(locale);
if (rb.containsKey(key)) {
caldata = Integer.parseInt(rb.getString(key));
} else {
caldata = 0;
}
cache.put(cacheKey,
new ResourceReference(cacheKey, (Object) caldata, referenceQueue));
}
return caldata;
}
public String getCollationData() {
String key = "Rule";
String coldata = "";
removeEmptyReferences();
ResourceReference data = cache.get(COLLATION_DATA_CACHEKEY);
if (data == null || ((coldata = (String) data.get()) == null)) {
ResourceBundle rb = localeData.getCollationData(locale);
if (rb.containsKey(key)) {
coldata = rb.getString(key);
}
cache.put(COLLATION_DATA_CACHEKEY,
new ResourceReference(COLLATION_DATA_CACHEKEY, (Object) coldata, referenceQueue));
}
return coldata;
}
public Object[] getDecimalFormatSymbolsData() {
Object[] dfsdata;
removeEmptyReferences();
ResourceReference data = cache.get(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY);
if (data == null || ((dfsdata = (Object[]) data.get()) == null)) {
// Note that only dfsdata[0] is prepared here in this method. Other
// elements are provided by the caller, yet they are cached here.
ResourceBundle rb = localeData.getNumberFormatData(locale);
dfsdata = new Object[3];
// NumberElements look up. First, try the Unicode extension
String numElemKey;
String numberType = locale.getUnicodeLocaleType("nu");
if (numberType != null) {
numElemKey = numberType + ".NumberElements";
if (rb.containsKey(numElemKey)) {
dfsdata[0] = rb.getStringArray(numElemKey);
}
}
// Next, try DefaultNumberingSystem value
if (dfsdata[0] == null && rb.containsKey("DefaultNumberingSystem")) {
numElemKey = rb.getString("DefaultNumberingSystem") + ".NumberElements";
if (rb.containsKey(numElemKey)) {
dfsdata[0] = rb.getStringArray(numElemKey);
}
}
// Last resort. No need to check the availability.
// Just let it throw MissingResourceException when needed.
if (dfsdata[0] == null) {
dfsdata[0] = rb.getStringArray("NumberElements");
}
cache.put(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY,
new ResourceReference(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY, (Object) dfsdata, referenceQueue));
}
return dfsdata;
}
public String getCurrencyName(String key) {
Object currencyName = null;
String cacheKey = CURRENCY_NAMES + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data != null && ((currencyName = data.get()) != null)) {
if (currencyName.equals(NULLOBJECT)) {
currencyName = null;
}
return (String) currencyName;
}
OpenListResourceBundle olrb = localeData.getCurrencyNames(locale);
if (olrb.containsKey(key)) {
currencyName = olrb.getObject(key);
cache.put(cacheKey,
new ResourceReference(cacheKey, currencyName, referenceQueue));
}
return (String) currencyName;
}
public String getLocaleName(String key) {
Object localeName = null;
String cacheKey = LOCALE_NAMES + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data != null && ((localeName = data.get()) != null)) {
if (localeName.equals(NULLOBJECT)) {
localeName = null;
}
return (String) localeName;
}
OpenListResourceBundle olrb = localeData.getLocaleNames(locale);
if (olrb.containsKey(key)) {
localeName = olrb.getObject(key);
cache.put(cacheKey,
new ResourceReference(cacheKey, localeName, referenceQueue));
}
return (String) localeName;
}
String[] getTimeZoneNames(String key) {
String[] names = null;
String cacheKey = TIME_ZONE_NAMES + '.' + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (Objects.isNull(data) || Objects.isNull((names = (String[]) data.get()))) {
TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
if (tznb.containsKey(key)) {
names = tznb.getStringArray(key);
cache.put(cacheKey,
new ResourceReference(cacheKey, (Object) names, referenceQueue));
}
}
return names;
}
@SuppressWarnings("unchecked")
Set<String> getZoneIDs() {
Set<String> zoneIDs = null;
removeEmptyReferences();
ResourceReference data = cache.get(ZONE_IDS_CACHEKEY);
if (data == null || ((zoneIDs = (Set<String>) data.get()) == null)) {
TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
zoneIDs = rb.keySet();
cache.put(ZONE_IDS_CACHEKEY,
new ResourceReference(ZONE_IDS_CACHEKEY, (Object) zoneIDs, referenceQueue));
}
return zoneIDs;
}
// zoneStrings are cached separately in TimeZoneNameUtility.
String[][] getZoneStrings() {
TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
Set<String> keyset = getZoneIDs();
// Use a LinkedHashSet to preseve the order
Set<String[]> value = new LinkedHashSet<>();
for (String key : keyset) {
value.add(rb.getStringArray(key));
}
// Add aliases data for CLDR
if (type == LocaleProviderAdapter.Type.CLDR) {
// Note: TimeZoneNamesBundle creates a String[] on each getStringArray call.
Map<String, String> aliases = ZoneInfo.getAliasTable();
for (String alias : aliases.keySet()) {
if (!keyset.contains(alias)) {
String tzid = aliases.get(alias);
if (keyset.contains(tzid)) {
String[] val = rb.getStringArray(tzid);
val[0] = alias;
value.add(val);
}
}
}
}
return value.toArray(new String[0][]);
}
String[] getCalendarNames(String key) {
String[] names = null;
String cacheKey = CALENDAR_NAMES + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data == null || ((names = (String[]) data.get()) == null)) {
ResourceBundle rb = localeData.getDateFormatData(locale);
if (rb.containsKey(key)) {
names = rb.getStringArray(key);
cache.put(cacheKey,
new ResourceReference(cacheKey, (Object) names, referenceQueue));
}
}
return names;
}
String[] getJavaTimeNames(String key) {
String[] names = null;
String cacheKey = CALENDAR_NAMES + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
if (data == null || ((names = (String[]) data.get()) == null)) {
ResourceBundle rb = getJavaTimeFormatData();
if (rb.containsKey(key)) {
names = rb.getStringArray(key);
cache.put(cacheKey,
new ResourceReference(cacheKey, (Object) names, referenceQueue));
}
}
return names;
}
public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) {
if (cal == null) {
cal = Calendar.getInstance(locale);
}
return getDateTimePattern(null, timeStyle, dateStyle, cal.getCalendarType());
}
/**
* Returns a date-time format pattern
* @param timeStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat,
* or -1 if not required
* @param dateStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat,
* or -1 if not required
* @param calType the calendar type for the pattern
* @return the pattern string
*/
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType) {
calType = CalendarDataUtility.normalizeCalendarType(calType);
String pattern;
pattern = getDateTimePattern("java.time.", timeStyle, dateStyle, calType);
if (pattern == null) {
pattern = getDateTimePattern(null, timeStyle, dateStyle, calType);
}
return pattern;
}
private String getDateTimePattern(String prefix, int timeStyle, int dateStyle, String calType) {
String pattern;
String timePattern = null;
String datePattern = null;
if (timeStyle >= 0) {
if (prefix != null) {
timePattern = getDateTimePattern(prefix, "TimePatterns", timeStyle, calType);
}
if (timePattern == null) {
timePattern = getDateTimePattern(null, "TimePatterns", timeStyle, calType);
}
}
if (dateStyle >= 0) {
if (prefix != null) {
datePattern = getDateTimePattern(prefix, "DatePatterns", dateStyle, calType);
}
if (datePattern == null) {
datePattern = getDateTimePattern(null, "DatePatterns", dateStyle, calType);
}
}
if (timeStyle >= 0) {
if (dateStyle >= 0) {
String dateTimePattern = null;
int dateTimeStyle = Math.max(dateStyle, timeStyle);
if (prefix != null) {
dateTimePattern = getDateTimePattern(prefix, "DateTimePatterns", dateTimeStyle, calType);
}
if (dateTimePattern == null) {
dateTimePattern = getDateTimePattern(null, "DateTimePatterns", dateTimeStyle, calType);
}
switch (dateTimePattern) {
case "{1} {0}":
pattern = datePattern + " " + timePattern;
break;
case "{0} {1}":
pattern = timePattern + " " + datePattern;
break;
default:
pattern = MessageFormat.format(dateTimePattern.replaceAll("'", "''"), timePattern, datePattern);
break;
}
} else {
pattern = timePattern;
}
} else if (dateStyle >= 0) {
pattern = datePattern;
} else {
throw new IllegalArgumentException("No date or time style specified");
}
return pattern;
}
public String[] getNumberPatterns() {
String[] numberPatterns = null;
removeEmptyReferences();
ResourceReference data = cache.get(NUMBER_PATTERNS_CACHEKEY);
if (data == null || ((numberPatterns = (String[]) data.get()) == null)) {
ResourceBundle resource = localeData.getNumberFormatData(locale);
numberPatterns = resource.getStringArray("NumberPatterns");
cache.put(NUMBER_PATTERNS_CACHEKEY,
new ResourceReference(NUMBER_PATTERNS_CACHEKEY, (Object) numberPatterns, referenceQueue));
}
return numberPatterns;
}
/**
* Returns the FormatData resource bundle of this LocaleResources.
* The FormatData should be used only for accessing extra
* resources required by JSR 310.
*/
public ResourceBundle getJavaTimeFormatData() {
ResourceBundle rb = localeData.getDateFormatData(locale);
if (rb instanceof ParallelListResourceBundle) {
localeData.setSupplementary((ParallelListResourceBundle) rb);
}
return rb;
}
private String getDateTimePattern(String prefix, String key, int styleIndex, String calendarType) {
StringBuilder sb = new StringBuilder();
if (prefix != null) {
sb.append(prefix);
}
if (!"gregory".equals(calendarType)) {
sb.append(calendarType).append('.');
}
sb.append(key);
String resourceKey = sb.toString();
String cacheKey = sb.insert(0, DATE_TIME_PATTERN).toString();
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
Object value = NULLOBJECT;
if (data == null || ((value = data.get()) == null)) {
ResourceBundle r = (prefix != null) ? getJavaTimeFormatData() : localeData.getDateFormatData(locale);
if (r.containsKey(resourceKey)) {
value = r.getStringArray(resourceKey);
} else {
assert !resourceKey.equals(key);
if (r.containsKey(key)) {
value = r.getStringArray(key);
}
}
cache.put(cacheKey,
new ResourceReference(cacheKey, value, referenceQueue));
}
if (value == NULLOBJECT) {
assert prefix != null;
return null;
}
// for DateTimePatterns. CLDR has multiple styles, while JRE has one.
String[] styles = (String[])value;
return (styles.length > 1 ? styles[styleIndex] : styles[0]);
}
private static class ResourceReference extends SoftReference<Object> {
private final String cacheKey;
ResourceReference(String cacheKey, Object o, ReferenceQueue<Object> q) {
super(o, q);
this.cacheKey = cacheKey;
}
String getCacheKey() {
return cacheKey;
}
}
}

View file

@ -0,0 +1,410 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.IllformedLocaleException;
import java.util.List;
import java.util.Locale;
import java.util.Locale.Builder;
import java.util.ResourceBundle.Control;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.LocaleServiceProvider;
import sun.util.logging.PlatformLogger;
/**
* An instance of this class holds a set of the third party implementations of a particular
* locale sensitive service, such as {@link java.util.spi.LocaleNameProvider}.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public final class LocaleServiceProviderPool {
/**
* A Map that holds singleton instances of this class. Each instance holds a
* set of provider implementations of a particular locale sensitive service.
*/
private static final ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools =
new ConcurrentHashMap<>();
/**
* A Map that retains Locale->provider mapping
*/
private final ConcurrentMap<Locale, List<LocaleServiceProvider>> providersCache =
new ConcurrentHashMap<>();
/**
* Available locales for this locale sensitive service. This also contains
* JRE's available locales
*/
private Set<Locale> availableLocales = null;
/**
* Provider class
*/
private final Class<? extends LocaleServiceProvider> providerClass;
/**
* Array of all Locale Sensitive SPI classes.
*
* We know "spiClasses" contains classes that extends LocaleServiceProvider,
* but generic array creation is not allowed, thus the "unchecked" warning
* is suppressed here.
*/
@SuppressWarnings("unchecked")
static final Class<LocaleServiceProvider>[] spiClasses =
(Class<LocaleServiceProvider>[]) new Class<?>[] {
java.text.spi.BreakIteratorProvider.class,
java.text.spi.CollatorProvider.class,
java.text.spi.DateFormatProvider.class,
java.text.spi.DateFormatSymbolsProvider.class,
java.text.spi.DecimalFormatSymbolsProvider.class,
java.text.spi.NumberFormatProvider.class,
java.util.spi.CurrencyNameProvider.class,
java.util.spi.LocaleNameProvider.class,
java.util.spi.TimeZoneNameProvider.class,
java.util.spi.CalendarDataProvider.class
};
/**
* A factory method that returns a singleton instance
*/
public static LocaleServiceProviderPool getPool(Class<? extends LocaleServiceProvider> providerClass) {
LocaleServiceProviderPool pool = poolOfPools.get(providerClass);
if (pool == null) {
LocaleServiceProviderPool newPool =
new LocaleServiceProviderPool(providerClass);
pool = poolOfPools.putIfAbsent(providerClass, newPool);
if (pool == null) {
pool = newPool;
}
}
return pool;
}
/**
* The sole constructor.
*
* @param c class of the locale sensitive service
*/
private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) {
providerClass = c;
}
static void config(Class<? extends Object> caller, String message) {
PlatformLogger logger = PlatformLogger.getLogger(caller.getCanonicalName());
logger.config(message);
}
/**
* Lazy loaded set of available locales.
* Loading all locales is a very long operation.
*/
private static class AllAvailableLocales {
/**
* Available locales for all locale sensitive services.
* This also contains JRE's available locales
*/
static final Locale[] allAvailableLocales;
static {
Set<Locale> all = new HashSet<>();
for (Class<? extends LocaleServiceProvider> c : spiClasses) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(c);
all.addAll(pool.getAvailableLocaleSet());
}
allAvailableLocales = all.toArray(new Locale[0]);
}
// No instantiation
private AllAvailableLocales() {
}
}
/**
* Returns an array of available locales for all the provider classes.
* This array is a merged array of all the locales that are provided by each
* provider, including the JRE.
*
* @return an array of the available locales for all provider classes
*/
public static Locale[] getAllAvailableLocales() {
return AllAvailableLocales.allAvailableLocales.clone();
}
/**
* Returns an array of available locales. This array is a
* merged array of all the locales that are provided by each
* provider, including the JRE.
*
* @return an array of the available locales
*/
public Locale[] getAvailableLocales() {
Set<Locale> locList = new HashSet<>();
locList.addAll(getAvailableLocaleSet());
// Make sure it all contains JRE's locales for compatibility.
locList.addAll(Arrays.asList(LocaleProviderAdapter.forJRE().getAvailableLocales()));
Locale[] tmp = new Locale[locList.size()];
locList.toArray(tmp);
return tmp;
}
/**
* Returns the union of locale sets that are available from
* each service provider. This method does NOT return the
* defensive copy.
*
* @return a set of available locales
*/
private synchronized Set<Locale> getAvailableLocaleSet() {
if (availableLocales == null) {
availableLocales = new HashSet<>();
for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
if (lda != null) {
LocaleServiceProvider lsp = lda.getLocaleServiceProvider(providerClass);
if (lsp != null) {
Locale[] locales = lsp.getAvailableLocales();
for (Locale locale: locales) {
availableLocales.add(getLookupLocale(locale));
}
}
}
}
}
return availableLocales;
}
/**
* Returns the provider's localized object for the specified
* locale.
*
* @param getter an object on which getObject() method
* is called to obtain the provider's instance.
* @param locale the given locale that is used as the starting one
* @param params provider specific parameters
* @return provider's instance, or null.
*/
public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
Locale locale,
Object... params) {
return getLocalizedObjectImpl(getter, locale, true, null, params);
}
/**
* Returns the provider's localized name for the specified
* locale.
*
* @param getter an object on which getObject() method
* is called to obtain the provider's instance.
* @param locale the given locale that is used as the starting one
* @param key the key string for name providers
* @param params provider specific parameters
* @return provider's instance, or null.
*/
public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
Locale locale,
String key,
Object... params) {
return getLocalizedObjectImpl(getter, locale, false, key, params);
}
/**
* Returns the provider's localized name for the specified
* locale.
*
* @param getter an object on which getObject() method
* is called to obtain the provider's instance.
* @param locale the given locale that is used as the starting one
* @param isObjectProvider flag designating object provder or not
* @param key the key string for name providers
* @param params provider specific parameters
* @return provider's instance, or null.
*/
public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
Locale locale,
Boolean isObjectProvider,
String key,
Object... params) {
return getLocalizedObjectImpl(getter, locale, isObjectProvider, key, params);
}
@SuppressWarnings("unchecked")
private <P extends LocaleServiceProvider, S> S getLocalizedObjectImpl(LocalizedObjectGetter<P, S> getter,
Locale locale,
boolean isObjectProvider,
String key,
Object... params) {
if (locale == null) {
throw new NullPointerException();
}
List<Locale> lookupLocales = getLookupLocales(locale);
for (Locale current : lookupLocales) {
S providersObj;
for (LocaleServiceProvider lsp: findProviders(current, isObjectProvider)) {
providersObj = getter.getObject((P)lsp, locale, key, params);
if (providersObj != null) {
return providersObj;
} else if (isObjectProvider) {
config(LocaleServiceProviderPool.class,
"A locale sensitive service provider returned null for a localized objects, which should not happen. provider: "
+ lsp + " locale: " + locale);
}
}
}
// not found.
return null;
}
/**
* Returns the list of locale service provider instances that support
* the specified locale.
*
* @param locale the given locale
* @return the list of locale data adapter types
*/
private List<LocaleServiceProvider> findProviders(Locale locale, boolean isObjectProvider) {
List<LocaleServiceProvider> providersList = providersCache.get(locale);
if (providersList == null) {
for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
if (lda != null) {
LocaleServiceProvider lsp = lda.getLocaleServiceProvider(providerClass);
if (lsp != null) {
if (lsp.isSupportedLocale(locale)) {
if (providersList == null) {
providersList = new ArrayList<>(2);
}
providersList.add(lsp);
if (isObjectProvider) {
break;
}
}
}
}
}
if (providersList == null) {
providersList = NULL_LIST;
}
List<LocaleServiceProvider> val = providersCache.putIfAbsent(locale, providersList);
if (val != null) {
providersList = val;
}
}
return providersList;
}
/**
* Returns a list of candidate locales for service look up.
* @param locale the input locale
* @return the list of candidate locales for the given locale
*/
static List<Locale> getLookupLocales(Locale locale) {
// Note: We currently use the default implementation of
// ResourceBundle.Control.getCandidateLocales. The result
// returned by getCandidateLocales are already normalized
// (no extensions) for service look up.
List<Locale> lookupLocales = Control.getNoFallbackControl(Control.FORMAT_DEFAULT)
.getCandidateLocales("", locale);
return lookupLocales;
}
/**
* Returns an instance of Locale used for service look up.
* The result Locale has no extensions except for ja_JP_JP
* and th_TH_TH
*
* @param locale the locale
* @return the locale used for service look up
*/
static Locale getLookupLocale(Locale locale) {
Locale lookupLocale = locale;
if (locale.hasExtensions()
&& !locale.equals(JRELocaleConstants.JA_JP_JP)
&& !locale.equals(JRELocaleConstants.TH_TH_TH)) {
// remove extensions
Builder locbld = new Builder();
try {
locbld.setLocale(locale);
locbld.clearExtensions();
lookupLocale = locbld.build();
} catch (IllformedLocaleException e) {
// A Locale with non-empty extensions
// should have well-formed fields except
// for ja_JP_JP and th_TH_TH. Therefore,
// it should never enter in this catch clause.
config(LocaleServiceProviderPool.class,
"A locale(" + locale + ") has non-empty extensions, but has illformed fields.");
// Fallback - script field will be lost.
lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant());
}
}
return lookupLocale;
}
/**
* A dummy locale service provider list that indicates there is no
* provider available
*/
private static final List<LocaleServiceProvider> NULL_LIST =
Collections.emptyList();
/**
* An interface to get a localized object for each locale sensitive
* service class.
*/
public interface LocalizedObjectGetter<P extends LocaleServiceProvider, S> {
/**
* Returns an object from the provider
*
* @param lsp the provider
* @param locale the locale
* @param key key string to localize, or null if the provider is not
* a name provider
* @param params provider specific params
* @return localized object from the provider
*/
public S getObject(P lsp,
Locale locale,
String key,
Object... params);
}
}

View file

@ -0,0 +1,227 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*/
package sun.util.locale.provider;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.spi.NumberFormatProvider;
import java.util.Currency;
import java.util.Locale;
import java.util.Set;
/**
* Concrete implementation of the {@link java.text.spi.NumberFormatProvider
* NumberFormatProvider} class for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class NumberFormatProviderImpl extends NumberFormatProvider implements AvailableLanguageTags {
// Constants used by factory methods to specify a style of format.
private static final int NUMBERSTYLE = 0;
private static final int CURRENCYSTYLE = 1;
private static final int PERCENTSTYLE = 2;
private static final int SCIENTIFICSTYLE = 3;
private static final int INTEGERSTYLE = 4;
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
public NumberFormatProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.forType(type).getAvailableLocales();
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a new <code>NumberFormat</code> instance which formats
* monetary values for the specified locale.
*
* @param locale the desired locale.
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a currency formatter
* @see java.text.NumberFormat#getCurrencyInstance(java.util.Locale)
*/
@Override
public NumberFormat getCurrencyInstance(Locale locale) {
return getInstance(locale, CURRENCYSTYLE);
}
/**
* Returns a new <code>NumberFormat</code> instance which formats
* integer values for the specified locale.
* The returned number format is configured to
* round floating point numbers to the nearest integer using
* half-even rounding (see {@link java.math.RoundingMode#HALF_EVEN HALF_EVEN})
* for formatting, and to parse only the integer part of
* an input string (see {@link
* java.text.NumberFormat#isParseIntegerOnly isParseIntegerOnly}).
*
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a number format for integer values
* @see java.text.NumberFormat#getIntegerInstance(java.util.Locale)
*/
@Override
public NumberFormat getIntegerInstance(Locale locale) {
return getInstance(locale, INTEGERSTYLE);
}
/**
* Returns a new general-purpose <code>NumberFormat</code> instance for
* the specified locale.
*
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a general-purpose number formatter
* @see java.text.NumberFormat#getNumberInstance(java.util.Locale)
*/
@Override
public NumberFormat getNumberInstance(Locale locale) {
return getInstance(locale, NUMBERSTYLE);
}
/**
* Returns a new <code>NumberFormat</code> instance which formats
* percentage values for the specified locale.
*
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a percent formatter
* @see java.text.NumberFormat#getPercentInstance(java.util.Locale)
*/
@Override
public NumberFormat getPercentInstance(Locale locale) {
return getInstance(locale, PERCENTSTYLE);
}
private NumberFormat getInstance(Locale locale,
int choice) {
if (locale == null) {
throw new NullPointerException();
}
LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
String[] numberPatterns = adapter.getLocaleResources(locale).getNumberPatterns();
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
if (choice == INTEGERSTYLE) {
format.setMaximumFractionDigits(0);
format.setDecimalSeparatorAlwaysShown(false);
format.setParseIntegerOnly(true);
} else if (choice == CURRENCYSTYLE) {
adjustForCurrencyDefaultFractionDigits(format, symbols);
}
return format;
}
/**
* Adjusts the minimum and maximum fraction digits to values that
* are reasonable for the currency's default fraction digits.
*/
private static void adjustForCurrencyDefaultFractionDigits(
DecimalFormat format, DecimalFormatSymbols symbols) {
Currency currency = symbols.getCurrency();
if (currency == null) {
try {
currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
} catch (IllegalArgumentException e) {
}
}
if (currency != null) {
int digits = currency.getDefaultFractionDigits();
if (digits != -1) {
int oldMinDigits = format.getMinimumFractionDigits();
// Common patterns are "#.##", "#.00", "#".
// Try to adjust all of them in a reasonable way.
if (oldMinDigits == format.getMaximumFractionDigits()) {
format.setMinimumFractionDigits(digits);
format.setMaximumFractionDigits(digits);
} else {
format.setMinimumFractionDigits(Math.min(digits, oldMinDigits));
format.setMaximumFractionDigits(digits);
}
}
}
}
@Override
public Set<String> getAvailableLanguageTags() {
return langtags;
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.List;
import java.util.Locale;
import sun.util.resources.LocaleData;
/**
* Accessor for LocaleData
*
* @author Naoto Sato
*/
public interface ResourceBundleBasedAdapter {
public LocaleData getLocaleData();
/**
* candidate locales customization
*/
public List<Locale> getCandidateLocales(String baseName, Locale locale);
}

View file

@ -0,0 +1,616 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.BreakIterator;
import java.text.Collator;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.text.spi.DateFormatProvider;
import java.text.spi.DateFormatSymbolsProvider;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.text.spi.NumberFormatProvider;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import java.util.spi.LocaleServiceProvider;
import java.util.spi.TimeZoneNameProvider;
/**
* LocaleProviderAdapter implementation for the installed SPI implementations.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
/**
* Returns the type of this LocaleProviderAdapter
*/
@Override
public LocaleProviderAdapter.Type getAdapterType() {
return LocaleProviderAdapter.Type.SPI;
}
@Override
protected <P extends LocaleServiceProvider> P findInstalledProvider(final Class<P> c) {
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction<P>() {
@Override
@SuppressWarnings(value={"unchecked", "deprecation"})
public P run() {
P delegate = null;
for (LocaleServiceProvider provider :
ServiceLoader.load(c, ClassLoader.getSystemClassLoader())) {
if (delegate == null) {
try {
delegate =
(P) Class.forName(SPILocaleProviderAdapter.class.getCanonicalName() +
"$" +
c.getSimpleName() +
"Delegate")
.newInstance();
} catch (ClassNotFoundException |
InstantiationException |
IllegalAccessException e) {
LocaleServiceProviderPool.config(SPILocaleProviderAdapter.class, e.toString());
return null;
}
}
((Delegate)delegate).addImpl(provider);
}
return delegate;
}
});
} catch (PrivilegedActionException e) {
LocaleServiceProviderPool.config(SPILocaleProviderAdapter.class, e.toString());
}
return null;
}
/*
* Delegate interface. All the implementations have to have the class name
* following "<provider class name>Delegate" convention.
*/
interface Delegate<P extends LocaleServiceProvider> {
public void addImpl(P impl);
public P getImpl(Locale locale);
}
/*
* Obtain the real SPI implementation, using locale fallback
*/
private static <P extends LocaleServiceProvider> P getImpl(Map<Locale, P> map, Locale locale) {
for (Locale l : LocaleServiceProviderPool.getLookupLocales(locale)) {
P ret = map.get(l);
if (ret != null) {
return ret;
}
}
return null;
}
/*
* Delegates for the actual SPI implementations.
*/
static class BreakIteratorProviderDelegate extends BreakIteratorProvider
implements Delegate<BreakIteratorProvider> {
private final ConcurrentMap<Locale, BreakIteratorProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(BreakIteratorProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public BreakIteratorProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public BreakIterator getWordInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getWordInstance(locale);
}
@Override
public BreakIterator getLineInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getLineInstance(locale);
}
@Override
public BreakIterator getCharacterInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getCharacterInstance(locale);
}
@Override
public BreakIterator getSentenceInstance(Locale locale) {
BreakIteratorProvider bip = getImpl(locale);
assert bip != null;
return bip.getSentenceInstance(locale);
}
}
static class CollatorProviderDelegate extends CollatorProvider implements Delegate<CollatorProvider> {
private final ConcurrentMap<Locale, CollatorProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(CollatorProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public CollatorProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public Collator getInstance(Locale locale) {
CollatorProvider cp = getImpl(locale);
assert cp != null;
return cp.getInstance(locale);
}
}
static class DateFormatProviderDelegate extends DateFormatProvider
implements Delegate<DateFormatProvider> {
private final ConcurrentMap<Locale, DateFormatProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(DateFormatProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public DateFormatProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public DateFormat getTimeInstance(int style, Locale locale) {
DateFormatProvider dfp = getImpl(locale);
assert dfp != null;
return dfp.getTimeInstance(style, locale);
}
@Override
public DateFormat getDateInstance(int style, Locale locale) {
DateFormatProvider dfp = getImpl(locale);
assert dfp != null;
return dfp.getDateInstance(style, locale);
}
@Override
public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) {
DateFormatProvider dfp = getImpl(locale);
assert dfp != null;
return dfp.getDateTimeInstance(dateStyle, timeStyle, locale);
}
}
static class DateFormatSymbolsProviderDelegate extends DateFormatSymbolsProvider
implements Delegate<DateFormatSymbolsProvider> {
private final ConcurrentMap<Locale, DateFormatSymbolsProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(DateFormatSymbolsProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public DateFormatSymbolsProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public DateFormatSymbols getInstance(Locale locale) {
DateFormatSymbolsProvider dfsp = getImpl(locale);
assert dfsp != null;
return dfsp.getInstance(locale);
}
}
static class DecimalFormatSymbolsProviderDelegate extends DecimalFormatSymbolsProvider
implements Delegate<DecimalFormatSymbolsProvider> {
private final ConcurrentMap<Locale, DecimalFormatSymbolsProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(DecimalFormatSymbolsProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public DecimalFormatSymbolsProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public DecimalFormatSymbols getInstance(Locale locale) {
DecimalFormatSymbolsProvider dfsp = getImpl(locale);
assert dfsp != null;
return dfsp.getInstance(locale);
}
}
static class NumberFormatProviderDelegate extends NumberFormatProvider
implements Delegate<NumberFormatProvider> {
private final ConcurrentMap<Locale, NumberFormatProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(NumberFormatProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public NumberFormatProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public NumberFormat getCurrencyInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getCurrencyInstance(locale);
}
@Override
public NumberFormat getIntegerInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getIntegerInstance(locale);
}
@Override
public NumberFormat getNumberInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getNumberInstance(locale);
}
@Override
public NumberFormat getPercentInstance(Locale locale) {
NumberFormatProvider nfp = getImpl(locale);
assert nfp != null;
return nfp.getPercentInstance(locale);
}
}
static class CalendarDataProviderDelegate extends CalendarDataProvider
implements Delegate<CalendarDataProvider> {
private final ConcurrentMap<Locale, CalendarDataProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(CalendarDataProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public CalendarDataProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public int getFirstDayOfWeek(Locale locale) {
CalendarDataProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getFirstDayOfWeek(locale);
}
@Override
public int getMinimalDaysInFirstWeek(Locale locale) {
CalendarDataProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getMinimalDaysInFirstWeek(locale);
}
}
static class CalendarNameProviderDelegate extends CalendarNameProvider
implements Delegate<CalendarNameProvider> {
private final ConcurrentMap<Locale, CalendarNameProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(CalendarNameProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public CalendarNameProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public String getDisplayName(String calendarType,
int field, int value,
int style, Locale locale) {
CalendarNameProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getDisplayName(calendarType, field, value, style, locale);
}
@Override
public Map<String, Integer> getDisplayNames(String calendarType,
int field, int style,
Locale locale) {
CalendarNameProvider cdp = getImpl(locale);
assert cdp != null;
return cdp.getDisplayNames(calendarType, field, style, locale);
}
}
static class CurrencyNameProviderDelegate extends CurrencyNameProvider
implements Delegate<CurrencyNameProvider> {
private final ConcurrentMap<Locale, CurrencyNameProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(CurrencyNameProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public CurrencyNameProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public String getSymbol(String currencyCode, Locale locale) {
CurrencyNameProvider cnp = getImpl(locale);
assert cnp != null;
return cnp.getSymbol(currencyCode, locale);
}
@Override
public String getDisplayName(String currencyCode, Locale locale) {
CurrencyNameProvider cnp = getImpl(locale);
assert cnp != null;
return cnp.getDisplayName(currencyCode, locale);
}
}
static class LocaleNameProviderDelegate extends LocaleNameProvider
implements Delegate<LocaleNameProvider> {
private final ConcurrentMap<Locale, LocaleNameProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(LocaleNameProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public LocaleNameProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public String getDisplayLanguage(String languageCode, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayLanguage(languageCode, locale);
}
@Override
public String getDisplayScript(String scriptCode, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayScript(scriptCode, locale);
}
@Override
public String getDisplayCountry(String countryCode, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayCountry(countryCode, locale);
}
@Override
public String getDisplayVariant(String variant, Locale locale) {
LocaleNameProvider lnp = getImpl(locale);
assert lnp != null;
return lnp.getDisplayVariant(variant, locale);
}
}
static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider
implements Delegate<TimeZoneNameProvider> {
private final ConcurrentMap<Locale, TimeZoneNameProvider> map = new ConcurrentHashMap<>();
@Override
public void addImpl(TimeZoneNameProvider impl) {
for (Locale l : impl.getAvailableLocales()) {
map.putIfAbsent(l, impl);
}
}
@Override
public TimeZoneNameProvider getImpl(Locale locale) {
return SPILocaleProviderAdapter.getImpl(map, locale);
}
@Override
public Locale[] getAvailableLocales() {
return map.keySet().toArray(new Locale[0]);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return map.containsKey(locale);
}
@Override
public String getDisplayName(String ID, boolean daylight, int style, Locale locale) {
TimeZoneNameProvider tznp = getImpl(locale);
assert tznp != null;
return tznp.getDisplayName(ID, daylight, style, locale);
}
@Override
public String getGenericDisplayName(String ID, int style, Locale locale) {
TimeZoneNameProvider tznp = getImpl(locale);
assert tznp != null;
return tznp.getGenericDisplayName(ID, style, locale);
}
}
}

View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
import java.util.spi.TimeZoneNameProvider;
import sun.util.calendar.ZoneInfoFile;
/**
* Concrete implementation of the
* {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider} class
* for the JRE LocaleProviderAdapter.
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public class TimeZoneNameProviderImpl extends TimeZoneNameProvider {
private final LocaleProviderAdapter.Type type;
private final Set<String> langtags;
private static final String CLDR_NO_INHERITANCE_MARKER = "\u2205\u2205\u2205";
TimeZoneNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
this.type = type;
this.langtags = langtags;
}
/**
* Returns an array of all locales for which this locale service provider
* can provide localized objects or names.
*
* @return An array of all locales for which this locale service provider
* can provide localized objects or names.
*/
@Override
public Locale[] getAvailableLocales() {
return LocaleProviderAdapter.toLocaleArray(langtags);
}
@Override
public boolean isSupportedLocale(Locale locale) {
return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
}
/**
* Returns a name for the given time zone ID that's suitable for
* presentation to the user in the specified locale. The given time
* zone ID is "GMT" or one of the names defined using "Zone" entries
* in the "tz database", a public domain time zone database at
* <a href="ftp://elsie.nci.nih.gov/pub/">ftp://elsie.nci.nih.gov/pub/</a>.
* The data of this database is contained in a file whose name starts with
* "tzdata", and the specification of the data format is part of the zic.8
* man page, which is contained in a file whose name starts with "tzcode".
* <p>
* If <code>daylight</code> is true, the method should return a name
* appropriate for daylight saving time even if the specified time zone
* has not observed daylight saving time in the past.
*
* @param id a time zone ID string
* @param daylight if true, return the daylight saving name.
* @param style either {@link java.util.TimeZone#LONG TimeZone.LONG} or
* {@link java.util.TimeZone#SHORT TimeZone.SHORT}
* @param locale the desired locale
* @return the human-readable name of the given time zone in the
* given locale, or null if it's not available.
* @exception IllegalArgumentException if <code>style</code> is invalid,
* or <code>locale</code> isn't one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @exception NullPointerException if <code>ID</code> or <code>locale</code>
* is null
* @see java.util.TimeZone#getDisplayName(boolean, int, java.util.Locale)
*/
@Override
public String getDisplayName(String id, boolean daylight, int style, Locale locale) {
String[] names = getDisplayNameArray(id, locale);
if (Objects.nonNull(names)) {
assert names.length >= 7;
int index = daylight ? 3 : 1;
if (style == TimeZone.SHORT) {
index++;
}
return names[index];
}
return null;
}
@Override
public String getGenericDisplayName(String id, int style, Locale locale) {
String[] names = getDisplayNameArray(id, locale);
if (Objects.nonNull(names)) {
assert names.length >= 7;
return names[(style == TimeZone.LONG) ? 5 : 6];
}
return null;
}
private String[] getDisplayNameArray(String id, Locale locale) {
Objects.requireNonNull(id);
Objects.requireNonNull(locale);
String[] ret =
LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id);
if (Objects.nonNull(ret) && type == LocaleProviderAdapter.Type.CLDR) {
// check for CLDR's "no inheritance marker"
for (int index = 0; index < ret.length; index++) {
TimeZone tz = null;
if (CLDR_NO_INHERITANCE_MARKER.equals(ret[index])) {
if (Objects.isNull(tz)) {
tz = TimeZone.getTimeZone(id);
}
int offset = tz.getRawOffset();
if (index == 3 || index == 4) { // daylight
offset += tz.getDSTSavings();
}
ret[index] = ZoneInfoFile.toCustomID(offset);
}
}
}
return ret;
}
/**
* Returns a String[][] as the DateFormatSymbols.getZoneStrings() value for
* the given locale. This method is package private.
*
* @param locale a Locale for time zone names
* @return an array of time zone names arrays
*/
String[][] getZoneStrings(Locale locale) {
return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getZoneStrings();
}
}

View file

@ -0,0 +1,266 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.locale.provider;
import java.lang.ref.SoftReference;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.spi.TimeZoneNameProvider;
import sun.util.calendar.ZoneInfo;
/**
* Utility class that deals with the localized time zone names
*
* @author Naoto Sato
* @author Masayoshi Okutsu
*/
public final class TimeZoneNameUtility {
/**
* cache to hold time zone localized strings. Keyed by Locale
*/
private static final ConcurrentHashMap<Locale, SoftReference<String[][]>> cachedZoneData =
new ConcurrentHashMap<>();
/**
* Cache for managing display names per timezone per locale
* The structure is:
* Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
*/
private static final Map<String, SoftReference<Map<Locale, String[]>>> cachedDisplayNames =
new ConcurrentHashMap<>();
/**
* get time zone localized strings. Enumerate all keys.
*/
public static String[][] getZoneStrings(Locale locale) {
String[][] zones;
SoftReference<String[][]> data = cachedZoneData.get(locale);
if (data == null || ((zones = data.get()) == null)) {
zones = loadZoneStrings(locale);
data = new SoftReference<>(zones);
cachedZoneData.put(locale, data);
}
return zones;
}
private static String[][] loadZoneStrings(Locale locale) {
// If the provider is a TimeZoneNameProviderImpl, call its getZoneStrings
// in order to avoid per-ID retrieval.
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(TimeZoneNameProvider.class, locale);
TimeZoneNameProvider provider = adapter.getTimeZoneNameProvider();
if (provider instanceof TimeZoneNameProviderImpl) {
String[][] zoneStrings = ((TimeZoneNameProviderImpl)provider).getZoneStrings(locale);
if (zoneStrings.length == 0 && locale.equals(Locale.ROOT)) {
// Unlike other *Name provider, zoneStrings search won't do the fallback
// name search. If the ResourceBundle found for the root locale contains no
// zoneStrings, just use the one for English, assuming English bundle
// contains all the tzids and their names.
zoneStrings= getZoneStrings(Locale.ENGLISH);
}
return zoneStrings;
}
// Performs per-ID retrieval.
Set<String> zoneIDs = LocaleProviderAdapter.forJRE().getLocaleResources(locale).getZoneIDs();
List<String[]> zones = new LinkedList<>();
for (String key : zoneIDs) {
String[] names = retrieveDisplayNamesImpl(key, locale);
if (names != null) {
zones.add(names);
}
}
String[][] zonesArray = new String[zones.size()][];
return zones.toArray(zonesArray);
}
/**
* Retrieve display names for a time zone ID.
*/
public static String[] retrieveDisplayNames(String id, Locale locale) {
Objects.requireNonNull(id);
Objects.requireNonNull(locale);
return retrieveDisplayNamesImpl(id, locale);
}
/**
* Retrieves a generic time zone display name for a time zone ID.
*
* @param id time zone ID
* @param style TimeZone.LONG or TimeZone.SHORT
* @param locale desired Locale
* @return the requested generic time zone display name, or null if not found.
*/
public static String retrieveGenericDisplayName(String id, int style, Locale locale) {
String[] names = retrieveDisplayNamesImpl(id, locale);
if (Objects.nonNull(names)) {
return names[6 - style];
} else {
return null;
}
}
/**
* Retrieves a standard or daylight-saving time name for the given time zone ID.
*
* @param id time zone ID
* @param daylight true for a daylight saving time name, or false for a standard time name
* @param style TimeZone.LONG or TimeZone.SHORT
* @param locale desired Locale
* @return the requested time zone name, or null if not found.
*/
public static String retrieveDisplayName(String id, boolean daylight, int style, Locale locale) {
String[] names = retrieveDisplayNamesImpl(id, locale);
if (Objects.nonNull(names)) {
return names[(daylight ? 4 : 2) - style];
} else {
return null;
}
}
private static String[] retrieveDisplayNamesImpl(String id, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
String[] names;
Map<Locale, String[]> perLocale = null;
SoftReference<Map<Locale, String[]>> ref = cachedDisplayNames.get(id);
if (Objects.nonNull(ref)) {
perLocale = ref.get();
if (Objects.nonNull(perLocale)) {
names = perLocale.get(locale);
if (Objects.nonNull(names)) {
return names;
}
}
}
// build names array
names = new String[7];
names[0] = id;
for (int i = 1; i <= 6; i ++) {
names[i] = pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale,
i<5 ? (i<3 ? "std" : "dst") : "generic", i%2, id);
}
if (Objects.isNull(perLocale)) {
perLocale = new ConcurrentHashMap<>();
}
perLocale.put(locale, names);
ref = new SoftReference<>(perLocale);
cachedDisplayNames.put(id, ref);
return names;
}
/**
* Obtains a localized time zone strings from a TimeZoneNameProvider
* implementation.
*/
private static class TimeZoneNameGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider,
String> {
private static final TimeZoneNameGetter INSTANCE =
new TimeZoneNameGetter();
@Override
public String getObject(TimeZoneNameProvider timeZoneNameProvider,
Locale locale,
String requestID,
Object... params) {
assert params.length == 2;
int style = (int) params[0];
String tzid = (String) params[1];
String value = getName(timeZoneNameProvider, locale, requestID, style, tzid);
if (value == null) {
Map<String, String> aliases = ZoneInfo.getAliasTable();
if (aliases != null) {
String canonicalID = aliases.get(tzid);
if (canonicalID != null) {
value = getName(timeZoneNameProvider, locale, requestID, style, canonicalID);
}
if (value == null) {
value = examineAliases(timeZoneNameProvider, locale, requestID,
canonicalID != null ? canonicalID : tzid, style, aliases);
}
}
}
return value;
}
private static String examineAliases(TimeZoneNameProvider tznp, Locale locale,
String requestID, String tzid, int style,
Map<String, String> aliases) {
for (Map.Entry<String, String> entry : aliases.entrySet()) {
if (entry.getValue().equals(tzid)) {
String alias = entry.getKey();
String name = getName(tznp, locale, requestID, style, alias);
if (name != null) {
return name;
}
name = examineAliases(tznp, locale, requestID, alias, style, aliases);
if (name != null) {
return name;
}
}
}
return null;
}
private static String getName(TimeZoneNameProvider timeZoneNameProvider,
Locale locale, String requestID, int style, String tzid) {
String value = null;
switch (requestID) {
case "std":
value = timeZoneNameProvider.getDisplayName(tzid, false, style, locale);
break;
case "dst":
value = timeZoneNameProvider.getDisplayName(tzid, true, style, locale);
break;
case "generic":
value = timeZoneNameProvider.getGenericDisplayName(tzid, style, locale);
break;
}
return value;
}
}
// No instantiation
private TimeZoneNameUtility() {
}
}

View file

@ -0,0 +1,516 @@
/*
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.logging;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.function.Supplier;
import jdk.internal.logger.LazyLoggers;
import jdk.internal.logger.LoggerWrapper;
/**
* Platform logger provides an API for the JRE components to log
* messages. This enables the runtime components to eliminate the
* static dependency of the logging facility and also defers the
* java.util.logging initialization until it is enabled.
* In addition, the PlatformLogger API can be used if the logging
* module does not exist.
*
* If the logging facility is not enabled, the platform loggers
* will output log messages per the default logging configuration
* (see below). In this implementation, it does not log the
* the stack frame information issuing the log message.
*
* When the logging facility is enabled (at startup or runtime),
* the backend logger will be created for each platform
* logger and all log messages will be forwarded to the Logger
* to handle.
*
* The PlatformLogger uses an underlying PlatformLogger.Bridge instance
* obtained by calling {@link PlatformLogger.Bridge#convert PlatformLogger.Bridge.convert(}
* {@link jdk.internal.logger.LazyLoggers#getLazyLogger(java.lang.String, java.lang.Class)
* jdk.internal.logger.LazyLoggers#getLazyLogger(name, PlatformLogger.class))}.
*
* Logging facility is "enabled" when one of the following
* conditions is met:
* 1) ServiceLoader.load({@link java.lang.System.LoggerFinder LoggerFinder.class},
* ClassLoader.getSystemClassLoader()).iterator().hasNext().
* 2) ServiceLoader.loadInstalled({@link jdk.internal.logger.DefaultLoggerFinder}).iterator().hasNext(),
* and 2.1) a system property "java.util.logging.config.class" or
* "java.util.logging.config.file" is set
* or 2.2) java.util.logging.LogManager or java.util.logging.Logger
* is referenced that will trigger the logging initialization.
*
* Default logging configuration:
*
* No LoggerFinder service implementation declared
* global logging level = INFO
* handlers = java.util.logging.ConsoleHandler
* java.util.logging.ConsoleHandler.level = INFO
* java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
*
* Limitation:
* {@code <JAVA_HOME>/conf/logging.properties} is the system-wide logging
* configuration defined in the specification and read in the
* default case to configure any java.util.logging.Logger instances.
* Platform loggers will not detect if {@code <JAVA_HOME>/conf/logging.properties}
* is modified. In other words, unless the java.util.logging API
* is used at runtime or the logging system properties is set,
* the platform loggers will use the default setting described above.
* The platform loggers are designed for JDK developers use and
* this limitation can be workaround with setting
* -Djava.util.logging.config.file system property.
* <br>
* Calling PlatformLogger.setLevel will not work when there is a custom
* LoggerFinder installed - and as a consequence {@link #setLevel setLevel}
* is now deprecated.
*
* @since 1.7
*/
public class PlatformLogger {
/**
* PlatformLogger logging levels.
*/
public static enum Level {
// The name and value must match that of {@code java.util.logging.Level}s.
// Declare in ascending order of the given value for binary search.
ALL(System.Logger.Level.ALL),
FINEST(System.Logger.Level.TRACE),
FINER(System.Logger.Level.TRACE),
FINE(System.Logger.Level.DEBUG),
CONFIG(System.Logger.Level.DEBUG),
INFO(System.Logger.Level.INFO),
WARNING(System.Logger.Level.WARNING),
SEVERE(System.Logger.Level.ERROR),
OFF(System.Logger.Level.OFF);
final System.Logger.Level systemLevel;
Level(System.Logger.Level systemLevel) {
this.systemLevel = systemLevel;
}
// The integer values must match that of {@code java.util.logging.Level}
// objects.
private static final int SEVERITY_OFF = Integer.MAX_VALUE;
private static final int SEVERITY_SEVERE = 1000;
private static final int SEVERITY_WARNING = 900;
private static final int SEVERITY_INFO = 800;
private static final int SEVERITY_CONFIG = 700;
private static final int SEVERITY_FINE = 500;
private static final int SEVERITY_FINER = 400;
private static final int SEVERITY_FINEST = 300;
private static final int SEVERITY_ALL = Integer.MIN_VALUE;
// ascending order for binary search matching the list of enum constants
private static final int[] LEVEL_VALUES = new int[] {
SEVERITY_ALL, SEVERITY_FINEST, SEVERITY_FINER,
SEVERITY_FINE, SEVERITY_CONFIG, SEVERITY_INFO,
SEVERITY_WARNING, SEVERITY_SEVERE, SEVERITY_OFF
};
public System.Logger.Level systemLevel() {
return systemLevel;
}
public int intValue() {
return LEVEL_VALUES[this.ordinal()];
}
/**
* Maps a severity value to an effective logger level.
* @param level The severity of the messages that should be
* logged with a logger set to the returned level.
* @return The effective logger level, which is the nearest Level value
* whose severity is greater or equal to the given level.
* For level > SEVERE (OFF excluded), return SEVERE.
*/
public static Level valueOf(int level) {
switch (level) {
// ordering per the highest occurrences in the jdk source
// finest, fine, finer, info first
case SEVERITY_FINEST : return Level.FINEST;
case SEVERITY_FINE : return Level.FINE;
case SEVERITY_FINER : return Level.FINER;
case SEVERITY_INFO : return Level.INFO;
case SEVERITY_WARNING : return Level.WARNING;
case SEVERITY_CONFIG : return Level.CONFIG;
case SEVERITY_SEVERE : return Level.SEVERE;
case SEVERITY_OFF : return Level.OFF;
case SEVERITY_ALL : return Level.ALL;
}
// return the nearest Level value >= the given level,
// for level > SEVERE, return SEVERE and exclude OFF
int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);
return values()[i >= 0 ? i : (-i-1)];
}
}
/**
*
* The PlatformLogger.Bridge interface is implemented by the System.Logger
* objects returned by our default JUL provider - so that JRE classes using
* PlatformLogger see no difference when JUL is the actual backend.
*
* PlatformLogger is now only a thin adaptation layer over the same
* loggers than returned by java.lang.System.getLogger(String name).
*
* The recommendation for JRE classes going forward is to use
* java.lang.System.getLogger(String name), which will
* use Lazy Loggers when possible and necessary.
*
*/
public static interface Bridge {
/**
* Gets the name for this platform logger.
* @return the name of the platform logger.
*/
public String getName();
/**
* Returns true if a message of the given level would actually
* be logged by this logger.
* @param level the level
* @return whether a message of that level would be logged
*/
public boolean isLoggable(Level level);
public boolean isEnabled();
public void log(Level level, String msg);
public void log(Level level, String msg, Throwable thrown);
public void log(Level level, String msg, Object... params);
public void log(Level level, Supplier<String> msgSupplier);
public void log(Level level, Throwable thrown, Supplier<String> msgSupplier);
public void logp(Level level, String sourceClass, String sourceMethod, String msg);
public void logp(Level level, String sourceClass, String sourceMethod,
Supplier<String> msgSupplier);
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Object... params);
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Throwable thrown);
public void logp(Level level, String sourceClass, String sourceMethod,
Throwable thrown, Supplier<String> msgSupplier);
public void logrb(Level level, String sourceClass, String sourceMethod,
ResourceBundle bundle, String msg, Object... params);
public void logrb(Level level, String sourceClass, String sourceMethod,
ResourceBundle bundle, String msg, Throwable thrown);
public void logrb(Level level, ResourceBundle bundle, String msg,
Object... params);
public void logrb(Level level, ResourceBundle bundle, String msg,
Throwable thrown);
public static Bridge convert(System.Logger logger) {
if (logger instanceof PlatformLogger.Bridge) {
return (Bridge) logger;
} else {
return new LoggerWrapper<>(logger);
}
}
}
/**
* The {@code PlatformLogger.ConfigurableBridge} interface is used to
* implement the deprecated {@link PlatformLogger#setLevel} method.
*
* PlatformLogger is now only a thin adaptation layer over the same
* loggers than returned by java.lang.System.getLogger(String name).
*
* The recommendation for JRE classes going forward is to use
* java.lang.System.getLogger(String name), which will
* use Lazy Loggers when possible and necessary.
*
*/
public static interface ConfigurableBridge {
public abstract class LoggerConfiguration {
public abstract Level getPlatformLevel();
public abstract void setPlatformLevel(Level level);
}
public default LoggerConfiguration getLoggerConfiguration() {
return null;
}
public static LoggerConfiguration getLoggerConfiguration(PlatformLogger.Bridge logger) {
if (logger instanceof PlatformLogger.ConfigurableBridge) {
return ((ConfigurableBridge) logger).getLoggerConfiguration();
} else {
return null;
}
}
}
// Table of known loggers. Maps names to PlatformLoggers.
private static final Map<String,WeakReference<PlatformLogger>> loggers =
new HashMap<>();
/**
* Returns a PlatformLogger of a given name.
* @param name the name of the logger
* @return a PlatformLogger
*/
public static synchronized PlatformLogger getLogger(String name) {
PlatformLogger log = null;
WeakReference<PlatformLogger> ref = loggers.get(name);
if (ref != null) {
log = ref.get();
}
if (log == null) {
log = new PlatformLogger(PlatformLogger.Bridge.convert(
// We pass PlatformLogger.class.getModule() (java.base)
// rather than the actual module of the caller
// because we want PlatformLoggers to be system loggers: we
// won't need to resolve any resource bundles anyway.
// Note: Many unit tests depend on the fact that
// PlatformLogger.getLoggerFromFinder is not caller
// sensitive, and this strategy ensure that the tests
// still pass.
LazyLoggers.getLazyLogger(name, PlatformLogger.class.getModule())));
loggers.put(name, new WeakReference<>(log));
}
return log;
}
// The system loggerProxy returned by LazyLoggers
// This may be a lazy logger - see jdk.internal.logger.LazyLoggers,
// or may be a Logger instance (or a wrapper thereof).
//
private final PlatformLogger.Bridge loggerProxy;
private PlatformLogger(PlatformLogger.Bridge loggerProxy) {
this.loggerProxy = loggerProxy;
}
/**
* A convenience method to test if the logger is turned off.
* (i.e. its level is OFF).
* @return whether the logger is turned off.
*/
public boolean isEnabled() {
return loggerProxy.isEnabled();
}
/**
* Gets the name for this platform logger.
* @return the name of the platform logger.
*/
public String getName() {
return loggerProxy.getName();
}
/**
* Returns true if a message of the given level would actually
* be logged by this logger.
* @param level the level
* @return whether a message of that level would be logged
*/
public boolean isLoggable(Level level) {
if (level == null) {
throw new NullPointerException();
}
return loggerProxy.isLoggable(level);
}
/**
* Get the log level that has been specified for this PlatformLogger.
* The result may be null, which means that this logger's
* effective level will be inherited from its parent.
*
* @return this PlatformLogger's level
*/
public Level level() {
final ConfigurableBridge.LoggerConfiguration spi =
PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);
return spi == null ? null : spi.getPlatformLevel();
}
/**
* Set the log level specifying which message levels will be
* logged by this logger. Message levels lower than this
* value will be discarded. The level value {@link Level#OFF}
* can be used to turn off logging.
* <p>
* If the new level is null, it means that this node should
* inherit its level from its nearest ancestor with a specific
* (non-null) level value.
*
* @param newLevel the new value for the log level (may be null)
* @deprecated Platform Loggers should not be configured programmatically.
* This method will not work if a custom {@link
* java.lang.System.LoggerFinder} is installed.
*/
@Deprecated
public void setLevel(Level newLevel) {
final ConfigurableBridge.LoggerConfiguration spi =
PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);;
if (spi != null) {
spi.setPlatformLevel(newLevel);
}
}
/**
* Logs a SEVERE message.
* @param msg the message
*/
public void severe(String msg) {
loggerProxy.log(Level.SEVERE, msg, (Object[])null);
}
public void severe(String msg, Throwable t) {
loggerProxy.log(Level.SEVERE, msg, t);
}
public void severe(String msg, Object... params) {
loggerProxy.log(Level.SEVERE, msg, params);
}
/**
* Logs a WARNING message.
* @param msg the message
*/
public void warning(String msg) {
loggerProxy.log(Level.WARNING, msg, (Object[])null);
}
public void warning(String msg, Throwable t) {
loggerProxy.log(Level.WARNING, msg, t);
}
public void warning(String msg, Object... params) {
loggerProxy.log(Level.WARNING, msg, params);
}
/**
* Logs an INFO message.
* @param msg the message
*/
public void info(String msg) {
loggerProxy.log(Level.INFO, msg, (Object[])null);
}
public void info(String msg, Throwable t) {
loggerProxy.log(Level.INFO, msg, t);
}
public void info(String msg, Object... params) {
loggerProxy.log(Level.INFO, msg, params);
}
/**
* Logs a CONFIG message.
* @param msg the message
*/
public void config(String msg) {
loggerProxy.log(Level.CONFIG, msg, (Object[])null);
}
public void config(String msg, Throwable t) {
loggerProxy.log(Level.CONFIG, msg, t);
}
public void config(String msg, Object... params) {
loggerProxy.log(Level.CONFIG, msg, params);
}
/**
* Logs a FINE message.
* @param msg the message
*/
public void fine(String msg) {
loggerProxy.log(Level.FINE, msg, (Object[])null);
}
public void fine(String msg, Throwable t) {
loggerProxy.log(Level.FINE, msg, t);
}
public void fine(String msg, Object... params) {
loggerProxy.log(Level.FINE, msg, params);
}
/**
* Logs a FINER message.
* @param msg the message
*/
public void finer(String msg) {
loggerProxy.log(Level.FINER, msg, (Object[])null);
}
public void finer(String msg, Throwable t) {
loggerProxy.log(Level.FINER, msg, t);
}
public void finer(String msg, Object... params) {
loggerProxy.log(Level.FINER, msg, params);
}
/**
* Logs a FINEST message.
* @param msg the message
*/
public void finest(String msg) {
loggerProxy.log(Level.FINEST, msg, (Object[])null);
}
public void finest(String msg, Throwable t) {
loggerProxy.log(Level.FINEST, msg, t);
}
public void finest(String msg, Object... params) {
loggerProxy.log(Level.FINEST, msg, params);
}
// ------------------------------------
// Maps used for Level conversion
// ------------------------------------
// This map is indexed by java.util.spi.Logger.Level.ordinal() and returns
// a PlatformLogger.Level
//
// ALL, TRACE, DEBUG, INFO, WARNING, ERROR, OFF
private static final Level[] spi2platformLevelMapping = {
Level.ALL, // mapped from ALL
Level.FINER, // mapped from TRACE
Level.FINE, // mapped from DEBUG
Level.INFO, // mapped from INFO
Level.WARNING, // mapped from WARNING
Level.SEVERE, // mapped from ERROR
Level.OFF // mapped from OFF
};
public static Level toPlatformLevel(java.lang.System.Logger.Level level) {
if (level == null) return null;
assert level.ordinal() < spi2platformLevelMapping.length;
return spi2platformLevelMapping[level.ordinal()];
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.Enumeration;
import java.util.ResourceBundle;
import java.util.Set;
/**
* BreakIteratorResourceBundle is an abstract class for loading BreakIterator
* data (rules or dictionary) from each module. An implementation class must
* implement getBreakIteratorInfo() that returns an instance of the
* corresponding BreakIteratorInfo (basename). The data name is taken from the
* BreakIteratorInfo instance.
*
* <p>For example, if the given key is "WordDictionary" and Locale is "th", the
* data name is taken from a BreakIteratorInfo_th and the key's value is
* "thai_dict". Its data thai_dict is loaded from the Module of the
* implementation class of this class.
*/
public abstract class BreakIteratorResourceBundle extends ResourceBundle {
// If any keys that are not for data names are added to BreakIteratorInfo*,
// those keys must be added to NON_DATA_KEYS.
private static final Set<String> NON_DATA_KEYS = Set.of("BreakIteratorClasses");
private volatile Set<String> keys;
/**
* Returns an instance of the corresponding {@code BreakIteratorInfo} (basename).
* The instance shouldn't have its parent.
*/
protected abstract ResourceBundle getBreakIteratorInfo();
@Override
protected Object handleGetObject(String key) {
if (NON_DATA_KEYS.contains(key)) {
return null;
}
ResourceBundle info = getBreakIteratorInfo();
if (!info.containsKey(key)) {
return null;
}
String path = getClass().getPackage().getName().replace('.', '/')
+ '/' + info.getString(key);
byte[] data;
try (InputStream is = getResourceAsStream(path)) {
data = is.readAllBytes();
} catch (Exception e) {
throw new InternalError("Can't load " + path, e);
}
return data;
}
private InputStream getResourceAsStream(String path) throws Exception {
PrivilegedExceptionAction<InputStream> pa;
pa = () -> getClass().getModule().getResourceAsStream(path);
InputStream is;
try {
is = AccessController.doPrivileged(pa);
} catch (PrivilegedActionException e) {
throw e.getException();
}
return is;
}
@Override
public Enumeration<String> getKeys() {
return Collections.enumeration(keySet());
}
@Override
protected Set<String> handleKeySet() {
if (keys == null) {
ResourceBundle info = getBreakIteratorInfo();
Set<String> k = info.keySet();
k.removeAll(NON_DATA_KEYS);
synchronized (this) {
if (keys == null) {
keys = k;
}
}
}
return keys;
}
}

View file

@ -0,0 +1,532 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.resources;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.ResourceBundleProvider;
import jdk.internal.misc.JavaUtilResourceBundleAccess;
import jdk.internal.misc.SharedSecrets;
/**
*/
public abstract class Bundles {
/** initial size of the bundle cache */
private static final int INITIAL_CACHE_SIZE = 32;
/** constant indicating that no resource bundle exists */
private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
@Override
public Enumeration<String> getKeys() { return null; }
@Override
protected Object handleGetObject(String key) { return null; }
@Override
public String toString() { return "NONEXISTENT_BUNDLE"; }
};
private static final JavaUtilResourceBundleAccess bundleAccess
= SharedSecrets.getJavaUtilResourceBundleAccess();
/**
* The cache is a map from cache keys (with bundle base name, locale, and
* class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
* BundleReference.
*
* The cache is a ConcurrentMap, allowing the cache to be searched
* concurrently by multiple threads. This will also allow the cache keys
* to be reclaimed along with the ClassLoaders they reference.
*
* This variable would be better named "cache", but we keep the old
* name for compatibility with some workarounds for bug 4212439.
*/
private static final ConcurrentMap<CacheKey, BundleReference> cacheList
= new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
/**
* Queue for reference objects referring to class loaders or bundles.
*/
private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
private Bundles() {
}
public static ResourceBundle of(String baseName, Locale locale, Strategy strategy) {
return loadBundleOf(baseName, locale, strategy);
}
private static ResourceBundle loadBundleOf(String baseName,
Locale targetLocale,
Strategy strategy) {
Objects.requireNonNull(baseName);
Objects.requireNonNull(targetLocale);
Objects.requireNonNull(strategy);
CacheKey cacheKey = new CacheKey(baseName, targetLocale);
ResourceBundle bundle = null;
// Quick lookup of the cache.
BundleReference bundleRef = cacheList.get(cacheKey);
if (bundleRef != null) {
bundle = bundleRef.get();
}
// If this bundle and all of its parents are valid,
// then return this bundle.
if (isValidBundle(bundle)) {
return bundle;
}
// Get the providers for loading the "leaf" bundle (i.e., bundle for
// targetLocale). If no providers are required for the bundle,
// none of its parents will require providers.
Class<? extends ResourceBundleProvider> type
= strategy.getResourceBundleProviderType(baseName, targetLocale);
if (type != null) {
@SuppressWarnings("unchecked")
ServiceLoader<ResourceBundleProvider> providers
= (ServiceLoader<ResourceBundleProvider>) ServiceLoader.loadInstalled(type);
cacheKey.setProviders(providers);
}
List<Locale> candidateLocales = strategy.getCandidateLocales(baseName, targetLocale);
bundle = findBundleOf(cacheKey, strategy, baseName, candidateLocales, 0);
if (bundle == null) {
throwMissingResourceException(baseName, targetLocale, cacheKey.getCause());
}
return bundle;
}
private static ResourceBundle findBundleOf(CacheKey cacheKey,
Strategy strategy,
String baseName,
List<Locale> candidateLocales,
int index) {
ResourceBundle parent = null;
Locale targetLocale = candidateLocales.get(index);
if (index != candidateLocales.size() - 1) {
parent = findBundleOf(cacheKey, strategy, baseName, candidateLocales, index + 1);
}
// Before we do the real loading work, see whether we need to
// do some housekeeping: If resource bundles have been nulled out,
// remove all related information from the cache.
cleanupCache();
// find an individual ResourceBundle in the cache
cacheKey.setLocale(targetLocale);
ResourceBundle bundle = findBundleInCache(cacheKey);
if (bundle != null) {
if (bundle == NONEXISTENT_BUNDLE) {
return parent;
}
if (bundleAccess.getParent(bundle) == parent) {
return bundle;
}
// Remove bundle from the cache.
BundleReference bundleRef = cacheList.get(cacheKey);
if (bundleRef != null && bundleRef.get() == bundle) {
cacheList.remove(cacheKey, bundleRef);
}
}
// Determine if providers should be used for loading the bundle.
// An assumption here is that if the leaf bundle of a look-up path is
// in java.base, all bundles of the path are in java.base.
// (e.g., en_US of path en_US -> en -> root is in java.base and the rest
// are in java.base as well)
// This assumption isn't valid for general bundle loading.
ServiceLoader<ResourceBundleProvider> providers = cacheKey.getProviders();
if (providers != null) {
if (strategy.getResourceBundleProviderType(baseName, targetLocale) == null) {
providers = null;
}
}
CacheKey constKey = (CacheKey) cacheKey.clone();
try {
if (providers != null) {
bundle = loadBundleFromProviders(baseName, targetLocale, providers, cacheKey);
} else {
try {
String bundleName = strategy.toBundleName(baseName, targetLocale);
Class<?> c = Class.forName(Bundles.class.getModule(), bundleName);
if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
@SuppressWarnings("unchecked")
Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
bundle = bundleAccess.newResourceBundle(bundleClass);
}
} catch (Exception e) {
cacheKey.setCause(e);
}
}
} finally {
if (constKey.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
}
if (bundle == null) {
// Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
// instance for the locale.
putBundleInCache(cacheKey, NONEXISTENT_BUNDLE);
return parent;
}
if (parent != null && bundleAccess.getParent(bundle) == null) {
bundleAccess.setParent(bundle, parent);
}
bundleAccess.setLocale(bundle, targetLocale);
bundleAccess.setName(bundle, baseName);
bundle = putBundleInCache(cacheKey, bundle);
return bundle;
}
private static void cleanupCache() {
Object ref;
while ((ref = referenceQueue.poll()) != null) {
cacheList.remove(((CacheKeyReference)ref).getCacheKey());
}
}
/**
* Loads ResourceBundle from service providers.
*/
private static ResourceBundle loadBundleFromProviders(String baseName,
Locale locale,
ServiceLoader<ResourceBundleProvider> providers,
CacheKey cacheKey)
{
return AccessController.doPrivileged(
new PrivilegedAction<>() {
public ResourceBundle run() {
for (Iterator<ResourceBundleProvider> itr = providers.iterator(); itr.hasNext(); ) {
try {
ResourceBundleProvider provider = itr.next();
ResourceBundle bundle = provider.getBundle(baseName, locale);
if (bundle != null) {
return bundle;
}
} catch (ServiceConfigurationError | SecurityException e) {
if (cacheKey != null) {
cacheKey.setCause(e);
}
}
}
return null;
}
});
}
private static boolean isValidBundle(ResourceBundle bundle) {
return bundle != null && bundle != NONEXISTENT_BUNDLE;
}
/**
* Throw a MissingResourceException with proper message
*/
private static void throwMissingResourceException(String baseName,
Locale locale,
Throwable cause) {
// If the cause is a MissingResourceException, avoid creating
// a long chain. (6355009)
if (cause instanceof MissingResourceException) {
cause = null;
}
MissingResourceException e;
e = new MissingResourceException("Can't find bundle for base name "
+ baseName + ", locale " + locale,
baseName + "_" + locale, // className
"");
e.initCause(cause);
throw e;
}
/**
* Finds a bundle in the cache.
*
* @param cacheKey the key to look up the cache
* @return the ResourceBundle found in the cache or null
*/
private static ResourceBundle findBundleInCache(CacheKey cacheKey) {
BundleReference bundleRef = cacheList.get(cacheKey);
if (bundleRef == null) {
return null;
}
return bundleRef.get();
}
/**
* Put a new bundle in the cache.
*
* @param cacheKey the key for the resource bundle
* @param bundle the resource bundle to be put in the cache
* @return the ResourceBundle for the cacheKey; if someone has put
* the bundle before this call, the one found in the cache is
* returned.
*/
private static ResourceBundle putBundleInCache(CacheKey cacheKey,
ResourceBundle bundle) {
CacheKey key = (CacheKey) cacheKey.clone();
BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
// Put the bundle in the cache if it's not been in the cache.
BundleReference result = cacheList.putIfAbsent(key, bundleRef);
// If someone else has put the same bundle in the cache before
// us, we should use the one in the cache.
if (result != null) {
ResourceBundle rb = result.get();
if (rb != null) {
// Clear the back link to the cache key
bundle = rb;
// Clear the reference in the BundleReference so that
// it won't be enqueued.
bundleRef.clear();
} else {
// Replace the invalid (garbage collected)
// instance with the valid one.
cacheList.put(key, bundleRef);
}
}
return bundle;
}
/**
* The Strategy interface defines methods that are called by Bundles.of during
* the resource bundle loading process.
*/
public static interface Strategy {
/**
* Returns a list of locales to be looked up for bundle loading.
*/
public List<Locale> getCandidateLocales(String baseName, Locale locale);
/**
* Returns the bundle name for the given baseName and locale.
*/
public String toBundleName(String baseName, Locale locale);
/**
* Returns the service provider type for the given baseName
* and locale, or null if no service providers should be used.
*/
public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,
Locale locale);
}
/**
* The common interface to get a CacheKey in LoaderReference and
* BundleReference.
*/
private static interface CacheKeyReference {
public CacheKey getCacheKey();
}
/**
* References to bundles are soft references so that they can be garbage
* collected when they have no hard references.
*/
private static class BundleReference extends SoftReference<ResourceBundle>
implements CacheKeyReference {
private final CacheKey cacheKey;
BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
super(referent, q);
cacheKey = key;
}
@Override
public CacheKey getCacheKey() {
return cacheKey;
}
}
/**
* Key used for cached resource bundles. The key checks the base
* name, the locale, and the class loader to determine if the
* resource is a match to the requested one. The loader may be
* null, but the base name and the locale must have a non-null
* value.
*/
private static class CacheKey implements Cloneable {
// These two are the actual keys for lookup in Map.
private String name;
private Locale locale;
// Placeholder for an error report by a Throwable
private Throwable cause;
// Hash code value cache to avoid recalculating the hash code
// of this instance.
private int hashCodeCache;
// The service loader to load bundles or null if no service loader
// is required.
private ServiceLoader<ResourceBundleProvider> providers;
CacheKey(String baseName, Locale locale) {
this.name = baseName;
this.locale = locale;
calculateHashCode();
}
String getName() {
return name;
}
CacheKey setName(String baseName) {
if (!this.name.equals(baseName)) {
this.name = baseName;
calculateHashCode();
}
return this;
}
Locale getLocale() {
return locale;
}
CacheKey setLocale(Locale locale) {
if (!this.locale.equals(locale)) {
this.locale = locale;
calculateHashCode();
}
return this;
}
ServiceLoader<ResourceBundleProvider> getProviders() {
return providers;
}
void setProviders(ServiceLoader<ResourceBundleProvider> providers) {
this.providers = providers;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
try {
final CacheKey otherEntry = (CacheKey)other;
//quick check to see if they are not equal
if (hashCodeCache != otherEntry.hashCodeCache) {
return false;
}
return locale.equals(otherEntry.locale)
&& name.equals(otherEntry.name);
} catch (NullPointerException | ClassCastException e) {
}
return false;
}
@Override
public int hashCode() {
return hashCodeCache;
}
private void calculateHashCode() {
hashCodeCache = name.hashCode() << 3;
hashCodeCache ^= locale.hashCode();
}
@Override
public Object clone() {
try {
CacheKey clone = (CacheKey) super.clone();
// Clear the reference to a Throwable
clone.cause = null;
// Clear the reference to a ServiceLoader
clone.providers = null;
return clone;
} catch (CloneNotSupportedException e) {
//this should never happen
throw new InternalError(e);
}
}
private void setCause(Throwable cause) {
if (this.cause == null) {
this.cause = cause;
} else {
// Override the cause if the previous one is
// ClassNotFoundException.
if (this.cause instanceof ClassNotFoundException) {
this.cause = cause;
}
}
}
private Throwable getCause() {
return cause;
}
@Override
public String toString() {
String l = locale.toString();
if (l.isEmpty()) {
if (!locale.getVariant().isEmpty()) {
l = "__" + locale.getVariant();
} else {
l = "\"\"";
}
}
return "CacheKey[" + name + ", lc=" + l + ")]";
}
}
}

View file

@ -0,0 +1,40 @@
#
# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
#
# The original version of this source code and documentation
# is copyrighted and owned by Taligent, Inc., a wholly-owned
# subsidiary of IBM. These materials are provided under terms
# of a License Agreement between Taligent and Sun. This technology
# is protected by multiple US and International patents.
#
# This notice and attribution to Taligent may not be removed.
# Taligent is a registered trademark of Taligent, Inc.
firstDayOfWeek=1
minimalDaysInFirstWeek=1

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface CalendarDataProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,43 @@
#
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
#
# The original version of this source code and documentation
# is copyrighted and owned by Taligent, Inc., a wholly-owned
# subsidiary of IBM. These materials are provided under terms
# of a License Agreement between Taligent and Sun. This technology
# is protected by multiple US and International patents.
#
# This notice and attribution to Taligent may not be removed.
# Taligent is a registered trademark of Taligent, Inc.
# This bundle is empty because the data of the base bundle
# is adequate for this locale.
# The bundle is necessary to prevent the resource
# bundle lookup from falling back to the default
# locale.

View file

@ -0,0 +1,501 @@
#
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# COPYRIGHT AND PERMISSION NOTICE
#
# Copyright (C) 1991-2012 Unicode, Inc. All rights reserved.
# Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of the Unicode data files and any associated documentation (the
# "Data Files") or Unicode software and any associated documentation
# (the "Software") to deal in the Data Files or Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, and/or sell copies of the Data
# Files or Software, and to permit persons to whom the Data Files or
# Software are furnished to do so, provided that (a) the above copyright
# notice(s) and this permission notice appear with all copies of the
# Data Files or Software, (b) both the above copyright notice(s) and
# this permission notice appear in associated documentation, and (c)
# there is clear notice in each modified Data File or in the Software as
# well as in the documentation associated with the Data File(s) or
# Software that the data or software has been modified.
#
# THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR
# ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR
# SOFTWARE.
#
# Except as contained in this notice, the name of a copyright holder
# shall not be used in advertising or otherwise to promote the sale, use
# or other dealings in these Data Files or Software without prior
# written authorization of the copyright holder.
ADP=ADP
AED=AED
AFA=AFA
AFN=AFN
ALL=ALL
AMD=AMD
ANG=ANG
AOA=AOA
ARS=ARS
ATS=ATS
AUD=AUD
AWG=AWG
AYM=AYM
AZM=AZM
AZN=AZN
BAM=BAM
BBD=BBD
BDT=BDT
BEF=BEF
BGL=BGL
BGN=BGN
BHD=BHD
BIF=BIF
BMD=BMD
BND=BND
BOB=BOB
BOV=BOV
BRL=BRL
BSD=BSD
BTN=BTN
BWP=BWP
BYB=BYB
BYN=BYN
BYR=BYR
BZD=BZD
CAD=CAD
CDF=CDF
CHF=CHF
CLF=CLF
CLP=CLP
CNY=CNY
COP=COP
CRC=CRC
CSD=CSD
CUC=CUC
CUP=CUP
CVE=CVE
CYP=CYP
CZK=CZK
DEM=DEM
DJF=DJF
DKK=DKK
DOP=DOP
DZD=DZD
EEK=EEK
EGP=EGP
ERN=ERN
ESP=ESP
ETB=ETB
EUR=EUR
FIM=FIM
FJD=FJD
FKP=FKP
FRF=FRF
GBP=GBP
GEL=GEL
GHC=GHC
GHS=GHS
GIP=GIP
GMD=GMD
GNF=GNF
GRD=GRD
GTQ=GTQ
GWP=GWP
GYD=GYD
HKD=HKD
HNL=HNL
HRK=HRK
HTG=HTG
HUF=HUF
IDR=IDR
IEP=IEP
ILS=ILS
INR=INR
IQD=IQD
IRR=IRR
ISK=ISK
ITL=ITL
JMD=JMD
JOD=JOD
JPY=JPY
KES=KES
KGS=KGS
KHR=KHR
KMF=KMF
KPW=KPW
KRW=KRW
KWD=KWD
KYD=KYD
KZT=KZT
LAK=LAK
LBP=LBP
LKR=LKR
LRD=LRD
LSL=LSL
LTL=LTL
LUF=LUF
LVL=LVL
LYD=LYD
MAD=MAD
MDL=MDL
MGA=MGA
MGF=MGF
MKD=MKD
MMK=MMK
MNT=MNT
MOP=MOP
MRO=MRO
MTL=MTL
MUR=MUR
MVR=MVR
MWK=MWK
MXN=MXN
MXV=MXV
MYR=MYR
MZM=MZM
MZN=MZN
NAD=NAD
NGN=NGN
NIO=NIO
NLG=NLG
NOK=NOK
NPR=NPR
NZD=NZD
OMR=OMR
PAB=PAB
PEN=PEN
PGK=PGK
PHP=PHP
PKR=PKR
PLN=PLN
PTE=PTE
PYG=PYG
QAR=QAR
ROL=ROL
RON=RON
RSD=RSD
RUB=RUB
RUR=RUR
RWF=RWF
SAR=SAR
SBD=SBD
SCR=SCR
SDD=SDD
SDG=SDG
SEK=SEK
SGD=SGD
SHP=SHP
SIT=SIT
SKK=SKK
SLL=SLL
SOS=SOS
SRD=SRD
SRG=SRG
SSP=SSP
STD=STD
SVC=SVC
SYP=SYP
SZL=SZL
THB=THB
TJS=TJS
TMM=TMM
TMT=TMT
TND=TND
TOP=TOP
TPE=TPE
TRL=TRL
TRY=TRY
TTD=TTD
TWD=TWD
TZS=TZS
UAH=UAH
UGX=UGX
USD=USD
USN=USN
USS=USS
UYU=UYU
UZS=UZS
VEB=VEB
VEF=VEF
VND=VND
VUV=VUV
WST=WST
XAF=XAF
XAG=XAG
XAU=XAU
XBA=XBA
XBB=XBB
XBC=XBC
XBD=XBD
XCD=XCD
XDR=XDR
XFO=XFO
XFU=XFU
XOF=XOF
XPD=XPD
XPF=XPF
XPT=XPT
XSU=XSU
XTS=XTS
XUA=XUA
XXX=XXX
YER=YER
YUM=YUM
ZAR=ZAR
ZMK=ZMK
ZMW=ZMW
ZWD=ZWD
ZWL=ZWL
ZWN=ZWN
ZWR=ZWR
adp=Andorran Peseta
aed=United Arab Emirates Dirham
afa=Afghan Afghani (1927-2002)
afn=Afghan Afghani
all=Albanian Lek
amd=Armenian Dram
ang=Netherlands Antillean Guilder
aoa=Angolan Kwanza
ars=Argentine Peso
ats=Austrian Schilling
aud=Australian Dollar
awg=Aruban Florin
azm=Azerbaijani Manat (1993-2006)
azn=Azerbaijani Manat
bam=Bosnia-Herzegovina Convertible Mark
bbd=Barbadian Dollar
bdt=Bangladeshi Taka
bef=Belgian Franc
bgl=Bulgarian Hard Lev
bgn=Bulgarian Lev
bhd=Bahraini Dinar
bif=Burundian Franc
bmd=Bermudan Dollar
bnd=Brunei Dollar
bob=Bolivian Boliviano
bov=Bolivian Mvdol
brl=Brazilian Real
bsd=Bahamian Dollar
btn=Bhutanese Ngultrum
bwp=Botswanan Pula
byb=Belarusian Ruble (1994-1999)
byn=Belarusian Ruble
byr=Belarusian Ruble (2000-2016)
bzd=Belize Dollar
cad=Canadian Dollar
cdf=Congolese Franc
chf=Swiss Franc
clf=Chilean Unit of Account (UF)
clp=Chilean Peso
cny=Chinese Yuan
cop=Colombian Peso
crc=Costa Rican Col\u00f3n
csd=Serbian Dinar (2002-2006)
cuc=Cuban Convertible Peso
cup=Cuban Peso
cve=Cape Verdean Escudo
cyp=Cypriot Pound
czk=Czech Republic Koruna
dem=German Mark
djf=Djiboutian Franc
dkk=Danish Krone
dop=Dominican Peso
dzd=Algerian Dinar
eek=Estonian Kroon
egp=Egyptian Pound
ern=Eritrean Nakfa
esp=Spanish Peseta
etb=Ethiopian Birr
eur=Euro
fim=Finnish Markka
fjd=Fijian Dollar
fkp=Falkland Islands Pound
frf=French Franc
gbp=British Pound Sterling
gel=Georgian Lari
ghc=Ghanaian Cedi (1979-2007)
ghs=Ghanaian Cedi
gip=Gibraltar Pound
gmd=Gambian Dalasi
gnf=Guinean Franc
grd=Greek Drachma
gtq=Guatemalan Quetzal
gwp=Guinea-Bissau Peso
gyd=Guyanaese Dollar
hkd=Hong Kong Dollar
hnl=Honduran Lempira
hrk=Kuna
htg=Haitian Gourde
huf=Hungarian Forint
idr=Indonesian Rupiah
iep=Irish Pound
ils=Israeli New Sheqel
inr=Indian Rupee
iqd=Iraqi Dinar
irr=Iranian Rial
isk=Icelandic Kr\u00f3na
itl=Italian Lira
jmd=Jamaican Dollar
jod=Jordanian Dinar
jpy=Japanese Yen
kes=Kenyan Shilling
kgs=Kyrgystani Som
khr=Cambodian Riel
kmf=Comorian Franc
kpw=North Korean Won
krw=South Korean Won
kwd=Kuwaiti Dinar
kyd=Cayman Islands Dollar
kzt=Kazakhstani Tenge
lak=Laotian Kip
lbp=Lebanese Pound
lkr=Sri Lankan Rupee
lrd=Liberian Dollar
lsl=Lesotho Loti
ltl=Lithuanian Litas
luf=Luxembourgian Franc
lvl=Latvian Lats
lyd=Libyan Dinar
mad=Moroccan Dirham
mdl=Moldovan Leu
mga=Malagasy Ariary
mgf=Malagasy Franc
mkd=Macedonian Denar
mmk=Myanma Kyat
mnt=Mongolian Tugrik
mop=Macanese Pataca
mro=Mauritanian Ouguiya
mtl=Maltese Lira
mur=Mauritian Rupee
mvr=Maldivian Rufiyaa
mwk=Malawian Malawi Kwacha
mxn=Mexican Peso
mxv=Mexican Investment Unit
myr=Malaysian Ringgit
mzm=Mozambican Metical (1980-2006)
mzn=Mozambican Metical
nad=Namibian Dollar
ngn=Nigerian Naira
nio=Nicaraguan C\u00f3rdoba
nlg=Dutch Guilder
nok=Norwegian Krone
npr=Nepalese Rupee
nzd=New Zealand Dollar
omr=Omani Rial
pab=Panamanian Balboa
pen=Peruvian Sol
pgk=Papua New Guinean Kina
php=Philippine Peso
pkr=Pakistani Rupee
pln=Polish Zloty
pte=Portuguese Escudo
pyg=Paraguayan Guarani
qar=Qatari Rial
rol=Romanian Leu (1952-2006)
ron=Romanian Leu
rsd=Serbian Dinar
rub=Russian Ruble
rur=Russian Ruble (1991-1998)
rwf=Rwandan Franc
sar=Saudi Riyal
sbd=Solomon Islands Dollar
scr=Seychellois Rupee
sdd=Sudanese Dinar (1992-2007)
sdg=Sudanese Pound
sek=Swedish Krona
sgd=Singapore Dollar
shp=Saint Helena Pound
sit=Slovenian Tolar
skk=Slovak Koruna
sll=Sierra Leonean Leone
sos=Somali Shilling
srd=Surinamese Dollar
srg=Surinamese Guilder
ssp=South Sudanese Pound
std=S\u00e3o Tom\u00e9 and Pr\u00edncipe Dobra
svc=Salvadoran Col\u00f3n
syp=Syrian Pound
szl=Swazi Lilangeni
thb=Thai Baht
tjs=Tajikistani Somoni
tmm=Turkmenistani Manat (1993-2009)
tmt=Turkmenistani Manat
tnd=Tunisian Dinar
top=Tongan Pa\u02bbanga
tpe=Timorese Escudo
trl=Turkish Lira (1922-2005)
try=Turkish Lira
ttd=Trinidad and Tobago Dollar
twd=New Taiwan Dollar
tzs=Tanzanian Shilling
uah=Ukrainian Hryvnia
ugx=Ugandan Shilling
usd=US Dollar
usn=US Dollar (Next day)
uss=US Dollar (Same day)
uyu=Uruguayan Peso
uzs=Uzbekistan Som
veb=Venezuelan Bol\u00edvar (1871-2008)
vef=Venezuelan Bol\u00edvar
vnd=Vietnamese Dong
vuv=Vanuatu Vatu
wst=Samoan Tala
xaf=CFA Franc BEAC
xag=Silver
xau=Gold
xba=European Composite Unit
xbb=European Monetary Unit
xbc=European Unit of Account (XBC)
xbd=European Unit of Account (XBD)
xcd=East Caribbean Dollar
xdr=Special Drawing Rights
xfo=French Gold Franc
xfu=French UIC-Franc
xof=CFA Franc BCEAO
xpd=Palladium
xpf=CFP Franc
xpt=Platinum
xsu=Sucre
xts=Testing Currency Code
xua=ADB Unit of Account
xxx=Unknown Currency
yer=Yemeni Rial
yum=Yugoslavian New Dinar (1994-2002)
zar=South African Rand
zmk=Zambian Kwacha
zwd=Zimbabwean Dollar (1980-2008)
zwl=Zimbabwean Dollar (2009)
zwr=Zimbabwean Dollar (2008)

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface CurrencyNamesProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,38 @@
#
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
#
# The original version of this source code and documentation
# is copyrighted and owned by Taligent, Inc., a wholly-owned
# subsidiary of IBM. These materials are provided under terms
# of a License Agreement between Taligent and Sun. This technology
# is protected by multiple US and International patents.
#
# This notice and attribution to Taligent may not be removed.
# Taligent is a registered trademark of Taligent, Inc.
USD=$

View file

@ -0,0 +1,348 @@
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.resources;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.spi.ResourceBundleProvider;
import sun.util.locale.provider.JRELocaleProviderAdapter;
import sun.util.locale.provider.LocaleProviderAdapter;
import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR;
import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE;
import sun.util.locale.provider.ResourceBundleBasedAdapter;
/**
* Provides information about and access to resource bundles in the
* sun.text.resources and sun.util.resources packages or in their corresponding
* packages for CLDR.
*
* @author Asmus Freytag
* @author Mark Davis
*/
public class LocaleData {
private static final ResourceBundle.Control defaultControl
= ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
private static final String DOTCLDR = ".cldr";
// Map of key (base name + locale) to candidates
private static final Map<String, List<Locale>> CANDIDATES_MAP = new ConcurrentHashMap<>();
private final LocaleProviderAdapter.Type type;
public LocaleData(LocaleProviderAdapter.Type type) {
this.type = type;
}
/**
* Gets a calendar data resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public ResourceBundle getCalendarData(Locale locale) {
return getBundle(type.getUtilResourcesPackage() + ".CalendarData", locale);
}
/**
* Gets a currency names resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public OpenListResourceBundle getCurrencyNames(Locale locale) {
return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".CurrencyNames", locale);
}
/**
* Gets a locale names resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public OpenListResourceBundle getLocaleNames(Locale locale) {
return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".LocaleNames", locale);
}
/**
* Gets a time zone names resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public TimeZoneNamesBundle getTimeZoneNames(Locale locale) {
return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale);
}
/**
* Gets a break iterator info resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public ResourceBundle getBreakIteratorInfo(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale);
}
/**
* Gets a break iterator resources resource bundle, using
* privileges to allow accessing a sun.* package.
*/
public ResourceBundle getBreakIteratorResources(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".BreakIteratorResources", locale);
}
/**
* Gets a collation data resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public ResourceBundle getCollationData(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".CollationData", locale);
}
/**
* Gets a date format data resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public ResourceBundle getDateFormatData(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".FormatData", locale);
}
public void setSupplementary(ParallelListResourceBundle formatData) {
if (!formatData.areParallelContentsComplete()) {
String suppName = type.getTextResourcesPackage() + ".JavaTimeSupplementary";
setSupplementary(suppName, formatData);
}
}
private boolean setSupplementary(String suppName, ParallelListResourceBundle formatData) {
ParallelListResourceBundle parent = (ParallelListResourceBundle) formatData.getParent();
boolean resetKeySet = false;
if (parent != null) {
resetKeySet = setSupplementary(suppName, parent);
}
OpenListResourceBundle supp = getSupplementary(suppName, formatData.getLocale());
formatData.setParallelContents(supp);
resetKeySet |= supp != null;
// If any parents or this bundle has parallel data, reset keyset to create
// a new keyset with the data.
if (resetKeySet) {
formatData.resetKeySet();
}
return resetKeySet;
}
/**
* Gets a number format data resource bundle, using privileges
* to allow accessing a sun.* package.
*/
public ResourceBundle getNumberFormatData(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".FormatData", locale);
}
public static ResourceBundle getBundle(final String baseName, final Locale locale) {
return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public ResourceBundle run() {
return Bundles.of(baseName, locale, LocaleDataStrategy.INSTANCE);
}
});
}
private static OpenListResourceBundle getSupplementary(final String baseName, final Locale locale) {
return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public OpenListResourceBundle run() {
OpenListResourceBundle rb = null;
try {
rb = (OpenListResourceBundle) Bundles.of(baseName, locale,
SupplementaryStrategy.INSTANCE);
} catch (MissingResourceException e) {
// return null if no supplementary is available
}
return rb;
}
});
}
private static abstract class LocaleDataResourceBundleProvider
implements ResourceBundleProvider {
/**
* Changes baseName to its module dependent package name and
* calls the super class implementation. For example,
* if the baseName is "sun.text.resources.FormatData" and locale is ja_JP,
* the baseName is changed to "sun.text.resources.ext.FormatData". If
* baseName contains ".cldr", such as "sun.text.resources.cldr.FormatData",
* the name is changed to "sun.text.resources.cldr.ext.FormatData".
*/
protected String toBundleName(String baseName, Locale locale) {
return LocaleDataStrategy.INSTANCE.toBundleName(baseName, locale);
}
}
/**
* A ResourceBundleProvider implementation for loading locale data
* resource bundles except for the java.time supplementary data.
*/
public static abstract class CommonResourceBundleProvider extends LocaleDataResourceBundleProvider {
}
/**
* A ResourceBundleProvider implementation for loading supplementary
* resource bundles for java.time.
*/
public static abstract class SupplementaryResourceBundleProvider extends LocaleDataResourceBundleProvider {
}
// Bundles.Strategy implementations
private static class LocaleDataStrategy implements Bundles.Strategy {
private static final LocaleDataStrategy INSTANCE = new LocaleDataStrategy();
// TODO: avoid hard-coded Locales
private static Set<Locale> JAVA_BASE_LOCALES
= Set.of(Locale.ROOT, Locale.ENGLISH, Locale.US, new Locale("en", "US", "POSIX"));
private LocaleDataStrategy() {
}
/*
* This method overrides the default implementation to search
* from a prebaked locale string list to determin the candidate
* locale list.
*
* @param baseName the resource bundle base name.
* locale the requested locale for the resource bundle.
* @return a list of candidate locales to search from.
* @exception NullPointerException if baseName or locale is null.
*/
@Override
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
String key = baseName + '-' + locale.toLanguageTag();
List<Locale> candidates = CANDIDATES_MAP.get(key);
if (candidates == null) {
LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE;
LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
candidates = adapter instanceof ResourceBundleBasedAdapter ?
((ResourceBundleBasedAdapter)adapter).getCandidateLocales(baseName, locale) :
defaultControl.getCandidateLocales(baseName, locale);
// Weed out Locales which are known to have no resource bundles
int lastDot = baseName.lastIndexOf('.');
String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName;
Set<String> langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category);
if (!langtags.isEmpty()) {
for (Iterator<Locale> itr = candidates.iterator(); itr.hasNext();) {
if (!adapter.isSupportedProviderLocale(itr.next(), langtags)) {
itr.remove();
}
}
}
// Force fallback to Locale.ENGLISH for CLDR time zone names support
if (locale.getLanguage() != "en"
&& type == CLDR && category.equals("TimeZoneNames")) {
candidates.add(candidates.size() - 1, Locale.ENGLISH);
}
CANDIDATES_MAP.putIfAbsent(key, candidates);
}
return candidates;
}
boolean inJavaBaseModule(String baseName, Locale locale) {
return JAVA_BASE_LOCALES.contains(locale);
}
@Override
public String toBundleName(String baseName, Locale locale) {
String newBaseName = baseName;
if (!inJavaBaseModule(baseName, locale)) {
if (baseName.startsWith(JRE.getUtilResourcesPackage())
|| baseName.startsWith(JRE.getTextResourcesPackage())) {
// Assume the lengths are the same.
assert JRE.getUtilResourcesPackage().length()
== JRE.getTextResourcesPackage().length();
int index = JRE.getUtilResourcesPackage().length();
if (baseName.indexOf(DOTCLDR, index) > 0) {
index += DOTCLDR.length();
}
newBaseName = baseName.substring(0, index + 1) + "ext"
+ baseName.substring(index);
}
}
return defaultControl.toBundleName(newBaseName, locale);
}
@Override
public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,
Locale locale) {
return inJavaBaseModule(baseName, locale) ?
null : CommonResourceBundleProvider.class;
}
}
private static class SupplementaryStrategy extends LocaleDataStrategy {
private static final SupplementaryStrategy INSTANCE
= new SupplementaryStrategy();
// TODO: avoid hard-coded Locales
private static Set<Locale> JAVA_BASE_LOCALES
= Set.of(Locale.ROOT, Locale.ENGLISH, Locale.US);
private SupplementaryStrategy() {
}
@Override
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
// Specifiy only the given locale
return Arrays.asList(locale);
}
@Override
public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,
Locale locale) {
return inJavaBaseModule(baseName, locale) ?
null : SupplementaryResourceBundleProvider.class;
}
@Override
boolean inJavaBaseModule(String baseName, Locale locale) {
return JAVA_BASE_LOCALES.contains(locale);
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface LocaleDataProvider extends ResourceBundleProvider {
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* Implements ResourceBundle for LocaleNames bundles that don't provide
* the complete set of locale names.
*/
public abstract class LocaleNamesBundle extends OpenListResourceBundle {
protected LocaleNamesBundle() {
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface LocaleNamesProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,41 @@
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
#
# The original version of this source code and documentation
# is copyrighted and owned by Taligent, Inc., a wholly-owned
# subsidiary of IBM. These materials are provided under terms
# of a License Agreement between Taligent and Sun. This technology
# is protected by multiple US and International patents.
#
# This notice and attribution to Taligent may not be removed.
# Taligent is a registered trademark of Taligent, Inc.
# This bundle is empty because the data of the base bundle
# is adequate for this locale.
# The bundle is necessary to prevent the resource
# bundle lookup from falling back to the default
# locale.

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.resources;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import sun.util.ResourceBundleEnumeration;
/**
* Subclass of <code>ResourceBundle</code> which mimics
* <code>ListResourceBundle</code>, but provides more hooks
* for specialized subclass behavior. For general description,
* see {@link java.util.ListResourceBundle}.
* <p>
* This class leaves handleGetObject non-final, and
* adds a method createMap which allows subclasses to
* use specialized Map implementations.
*/
public abstract class OpenListResourceBundle extends ResourceBundle {
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected OpenListResourceBundle() {
}
// Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
@Override
protected Object handleGetObject(String key) {
if (key == null) {
throw new NullPointerException();
}
loadLookupTablesIfNecessary();
return lookup.get(key); // this class ignores locales
}
/**
* Implementation of ResourceBundle.getKeys.
*/
@Override
public Enumeration<String> getKeys() {
ResourceBundle parentBundle = this.parent;
return new ResourceBundleEnumeration(handleKeySet(),
(parentBundle != null) ? parentBundle.getKeys() : null);
}
/**
* Returns a set of keys provided in this resource bundle,
* including no parents.
*/
@Override
protected Set<String> handleKeySet() {
loadLookupTablesIfNecessary();
return lookup.keySet();
}
@Override
public Set<String> keySet() {
if (keyset != null) {
return keyset;
}
Set<String> ks = createSet();
ks.addAll(handleKeySet());
if (parent != null) {
ks.addAll(parent.keySet());
}
synchronized (this) {
if (keyset == null) {
keyset = ks;
}
}
return keyset;
}
/**
* See ListResourceBundle class description.
*/
protected abstract Object[][] getContents();
/**
* Load lookup tables if they haven't been loaded already.
*/
void loadLookupTablesIfNecessary() {
if (lookup == null) {
loadLookup();
}
}
/**
* We lazily load the lookup hashtable. This function does the
* loading.
*/
private void loadLookup() {
Object[][] contents = getContents();
Map<String, Object> temp = createMap(contents.length);
for (int i = 0; i < contents.length; ++i) {
// key must be non-null String, value must be non-null
String key = (String) contents[i][0];
Object value = contents[i][1];
if (key == null || value == null) {
throw new NullPointerException();
}
temp.put(key, value);
}
synchronized (this) {
if (lookup == null) {
lookup = temp;
}
}
}
/**
* Lets subclasses provide specialized Map implementations.
* Default uses HashMap.
*/
protected <K, V> Map<K, V> createMap(int size) {
return new HashMap<>(size);
}
protected <E> Set<E> createSet() {
return new HashSet<>();
}
private volatile Map<String, Object> lookup;
private volatile Set<String> keyset;
}

View file

@ -0,0 +1,259 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicMarkableReference;
/**
* ParallelListResourceBundle is another variant of ListResourceBundle
* supporting "parallel" contents provided by another resource bundle
* (OpenListResourceBundle). Parallel contents, if any, are added into this
* bundle on demand.
*
* @author Masayoshi Okutsu
*/
public abstract class ParallelListResourceBundle extends ResourceBundle {
private volatile ConcurrentMap<String, Object> lookup;
private volatile Set<String> keyset;
private final AtomicMarkableReference<Object[][]> parallelContents
= new AtomicMarkableReference<>(null, false);
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected ParallelListResourceBundle() {
}
/**
* Returns an array in which each item is a pair of objects in an
* Object array. The first element of each pair is the key, which
* must be a String, and the second element is the value
* associated with that key. See the class description for
* details.
*
* @return an array of an Object array representing a key-value pair.
*/
protected abstract Object[][] getContents();
/**
* Returns the parent of this resource bundle or null if there's no parent.
*
* @return the parent or null if no parent
*/
ResourceBundle getParent() {
return parent;
}
/**
* Sets the parallel contents to the data given by rb. If rb is null, this
* bundle will be marked as `complete'.
*
* @param rb an OpenResourceBundle for parallel contents, or null indicating
* there are no parallel contents for this bundle
*/
public void setParallelContents(OpenListResourceBundle rb) {
if (rb == null) {
parallelContents.compareAndSet(null, null, false, true);
} else {
parallelContents.compareAndSet(null, rb.getContents(), false, false);
}
}
/**
* Returns true if any parallel contents have been set or if this bundle is
* marked as complete.
*
* @return true if any parallel contents have been processed
*/
boolean areParallelContentsComplete() {
// Quick check for `complete'
if (parallelContents.isMarked()) {
return true;
}
boolean[] done = new boolean[1];
Object[][] data = parallelContents.get(done);
return data != null || done[0];
}
@Override
protected Object handleGetObject(String key) {
if (key == null) {
throw new NullPointerException();
}
loadLookupTablesIfNecessary();
return lookup.get(key);
}
@Override
public Enumeration<String> getKeys() {
return Collections.enumeration(keySet());
}
@Override
public boolean containsKey(String key) {
return keySet().contains(key);
}
@Override
protected Set<String> handleKeySet() {
loadLookupTablesIfNecessary();
return lookup.keySet();
}
@Override
@SuppressWarnings("UnusedAssignment")
public Set<String> keySet() {
Set<String> ks;
while ((ks = keyset) == null) {
ks = new KeySet(handleKeySet(), parent);
synchronized (this) {
if (keyset == null) {
keyset = ks;
}
}
}
return ks;
}
/**
* Discards any cached keyset value. This method is called from
* LocaleData for re-creating a KeySet.
*/
synchronized void resetKeySet() {
keyset = null;
}
/**
* Loads the lookup table if they haven't been loaded already.
*/
void loadLookupTablesIfNecessary() {
ConcurrentMap<String, Object> map = lookup;
if (map == null) {
map = new ConcurrentHashMap<>();
for (Object[] item : getContents()) {
map.put((String) item[0], item[1]);
}
}
// If there's any parallel contents data, merge the data into map.
Object[][] data = parallelContents.getReference();
if (data != null) {
for (Object[] item : data) {
map.putIfAbsent((String) item[0], item[1]);
}
parallelContents.set(null, true);
}
if (lookup == null) {
synchronized (this) {
if (lookup == null) {
lookup = map;
}
}
}
}
/**
* This class implements the Set interface for
* ParallelListResourceBundle methods.
*/
private static class KeySet extends AbstractSet<String> {
private final Set<String> set;
private final ResourceBundle parent;
private KeySet(Set<String> set, ResourceBundle parent) {
this.set = set;
this.parent = parent;
}
@Override
public boolean contains(Object o) {
if (set.contains(o)) {
return true;
}
return (parent != null) ? parent.containsKey((String) o) : false;
}
@Override
public Iterator<String> iterator() {
if (parent == null) {
return set.iterator();
}
return new Iterator<>() {
private Iterator<String> itr = set.iterator();
private boolean usingParent;
@Override
public boolean hasNext() {
if (itr.hasNext()) {
return true;
}
if (!usingParent) {
Set<String> nextset = new HashSet<>(parent.keySet());
nextset.removeAll(set);
itr = nextset.iterator();
usingParent = true;
}
return itr.hasNext();
}
@Override
public String next() {
if (hasNext()) {
return itr.next();
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public int size() {
if (parent == null) {
return set.size();
}
Set<String> allset = new HashSet<>(set);
allset.addAll(parent.keySet());
return allset.size();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.resources;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Set;
/**
* Subclass of <code>ResourceBundle</code> with special
* functionality for time zone names. The additional functionality:
* <ul>
* <li>Preserves the order of entries in the <code>getContents</code>
* array for the enumeration returned by <code>getKeys</code>.
* <li>Inserts the time zone ID (the key of the bundle entries) into
* the string arrays returned by <code>handleGetObject</code>.
* </ul>
* All <code>TimeZoneNames</code> resource bundles must extend this
* class and implement the <code>getContents</code> method.
*/
public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
/**
* Maps time zone IDs to locale-specific names.
* The value returned is an array of five strings:
* <ul>
* <li>The time zone ID (same as the key, not localized).
* <li>The long name of the time zone in standard time (localized).
* <li>The short name of the time zone in standard time (localized).
* <li>The long name of the time zone in daylight savings time (localized).
* <li>The short name of the time zone in daylight savings time (localized).
* <li>The long name of the time zone in generic form (localized).
* <li>The short name of the time zone in generic form (localized).
* </ul>
* The localized names come from the subclasses's
* <code>getContents</code> implementations, while the time zone
* ID is inserted into the returned array by this method.
*/
@Override
public Object handleGetObject(String key) {
String[] contents = (String[]) super.handleGetObject(key);
if (Objects.isNull(contents)) {
return null;
}
int clen = contents.length;
String[] tmpobj = new String[7];
tmpobj[0] = key;
System.arraycopy(contents, 0, tmpobj, 1, clen);
return tmpobj;
}
/**
* Use LinkedHashMap to preserve the order of bundle entries.
*/
@Override
protected <K, V> Map<K, V> createMap(int size) {
return new LinkedHashMap<>(size);
}
/**
* Use LinkedHashSet to preserve the key order.
* @param <E> the type of elements
* @return a Set
*/
@Override
protected <E> Set<E> createSet() {
return new LinkedHashSet<>();
}
/**
* Provides key/value mappings for a specific
* resource bundle. Each entry of the array
* returned must be an array with two elements:
* <ul>
* <li>The key, which must be a string.
* <li>The value, which must be an array of
* four strings:
* <ul>
* <li>The long name of the time zone in standard time.
* <li>The short name of the time zone in standard time.
* <li>The long name of the time zone in daylight savings time.
* <li>The short name of the time zone in daylight savings time.
* </ul>
* </ul>
*/
protected abstract Object[][] getContents();
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface TimeZoneNamesProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
package sun.util.resources;
import sun.util.resources.TimeZoneNamesBundle;
public final class TimeZoneNames_en extends TimeZoneNamesBundle {
// This bundle is empty because the root bundle's content
// is adequate for this locale.
// The bundle is necessary to prevent the resource
// bundle lookup from falling back to the default
// locale.
protected final Object[][] getContents() {
return new Object[][] {
};
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources.cldr;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface CalendarDataProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources.cldr;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface CurrencyNamesProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources.cldr;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface LocaleNamesProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.resources.cldr;
import java.util.spi.ResourceBundleProvider;
/**
* An interface for the internal locale data provider for which {@code ResourceBundle}
* searches.
*/
public interface TimeZoneNamesProvider extends ResourceBundleProvider {
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.spi;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.spi.LocaleServiceProvider;
/**
* An abstract class for service providers that
* provide instances of the
* {@link java.util.Calendar Calendar} class.
*
* @since 1.8
*/
public abstract class CalendarProvider extends LocaleServiceProvider {
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected CalendarProvider() {
}
/**
* Returns a new <code>Calendar</code> instance for the
* specified locale.
*
* @param zone the time zone
* @param locale the desired locale
* @exception NullPointerException if <code>locale</code> is null
* @exception IllegalArgumentException if <code>locale</code> isn't
* one of the locales returned from
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @return a <code>Calendar</code> instance.
* @see java.util.Calendar#getInstance(java.util.Locale)
*/
public abstract Calendar getInstance(TimeZone zone, Locale locale);
}