feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.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.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
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.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 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;
|
||||
}
|
||||
|
||||
private static Locale[] availableLocales = null;
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
if (availableLocales == null) {
|
||||
Set<Locale> avail = new HashSet<>();
|
||||
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 NullProvider NULL_PROVIDER = new NullProvider();
|
||||
private static class NullProvider extends LocaleServiceProvider {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return new Locale[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
343
jdkSrc/jdk8/sun/util/locale/provider/BreakDictionary.java
Normal file
343
jdkSrc/jdk8/sun/util/locale/provider/BreakDictionary.java
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* 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.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.MissingResourceException;
|
||||
import sun.text.CompactByteArray;
|
||||
import sun.text.SupplementaryCharacterData;
|
||||
|
||||
/**
|
||||
* This is the class that represents the list of known words used by
|
||||
* DictionaryBasedBreakIterator. The conceptual data structure used
|
||||
* here is a trie: there is a node hanging off the root node for every
|
||||
* letter that can start a word. Each of these nodes has a node hanging
|
||||
* off of it for every letter that can be the second letter of a word
|
||||
* if this node is the first letter, and so on. The trie is represented
|
||||
* as a two-dimensional array that can be treated as a table of state
|
||||
* transitions. Indexes are used to compress this array, taking
|
||||
* advantage of the fact that this array will always be very sparse.
|
||||
*/
|
||||
class BreakDictionary {
|
||||
|
||||
//=========================================================================
|
||||
// data members
|
||||
//=========================================================================
|
||||
|
||||
/**
|
||||
* The version of the dictionary that was read in.
|
||||
*/
|
||||
private static int supportedVersion = 1;
|
||||
|
||||
/**
|
||||
* Maps from characters to column numbers. The main use of this is to
|
||||
* avoid making room in the array for empty columns.
|
||||
*/
|
||||
private CompactByteArray columnMap = null;
|
||||
private SupplementaryCharacterData supplementaryCharColumnMap = null;
|
||||
|
||||
/**
|
||||
* The number of actual columns in the table
|
||||
*/
|
||||
private int numCols;
|
||||
|
||||
/**
|
||||
* Columns are organized into groups of 32. This says how many
|
||||
* column groups. (We could calculate this, but we store the
|
||||
* value to avoid having to repeatedly calculate it.)
|
||||
*/
|
||||
private int numColGroups;
|
||||
|
||||
/**
|
||||
* The actual compressed state table. Each conceptual row represents
|
||||
* a state, and the cells in it contain the row numbers of the states
|
||||
* to transition to for each possible letter. 0 is used to indicate
|
||||
* an illegal combination of letters (i.e., the error state). The
|
||||
* table is compressed by eliminating all the unpopulated (i.e., zero)
|
||||
* cells. Multiple conceptual rows can then be doubled up in a single
|
||||
* physical row by sliding them up and possibly shifting them to one
|
||||
* side or the other so the populated cells don't collide. Indexes
|
||||
* are used to identify unpopulated cells and to locate populated cells.
|
||||
*/
|
||||
private short[] table = null;
|
||||
|
||||
/**
|
||||
* This index maps logical row numbers to physical row numbers
|
||||
*/
|
||||
private short[] rowIndex = null;
|
||||
|
||||
/**
|
||||
* A bitmap is used to tell which cells in the comceptual table are
|
||||
* populated. This array contains all the unique bit combinations
|
||||
* in that bitmap. If the table is more than 32 columns wide,
|
||||
* successive entries in this array are used for a single row.
|
||||
*/
|
||||
private int[] rowIndexFlags = null;
|
||||
|
||||
/**
|
||||
* This index maps from a logical row number into the bitmap table above.
|
||||
* (This keeps us from storing duplicate bitmap combinations.) Since there
|
||||
* are a lot of rows with only one populated cell, instead of wasting space
|
||||
* in the bitmap table, we just store a negative number in this index for
|
||||
* rows with one populated cell. The absolute value of that number is
|
||||
* the column number of the populated cell.
|
||||
*/
|
||||
private short[] rowIndexFlagsIndex = null;
|
||||
|
||||
/**
|
||||
* For each logical row, this index contains a constant that is added to
|
||||
* the logical column number to get the physical column number
|
||||
*/
|
||||
private byte[] rowIndexShifts = null;
|
||||
|
||||
//=========================================================================
|
||||
// deserialization
|
||||
//=========================================================================
|
||||
|
||||
BreakDictionary(String dictionaryName)
|
||||
throws IOException, MissingResourceException {
|
||||
|
||||
readDictionaryFile(dictionaryName);
|
||||
}
|
||||
|
||||
private void readDictionaryFile(final String dictionaryName)
|
||||
throws IOException, MissingResourceException {
|
||||
|
||||
BufferedInputStream in;
|
||||
try {
|
||||
in = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<BufferedInputStream>() {
|
||||
@Override
|
||||
public BufferedInputStream run() throws Exception {
|
||||
return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + dictionaryName));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (PrivilegedActionException e) {
|
||||
throw new InternalError(e.toString(), e);
|
||||
}
|
||||
|
||||
byte[] buf = new byte[8];
|
||||
if (in.read(buf) != 8) {
|
||||
throw new MissingResourceException("Wrong data length",
|
||||
dictionaryName, "");
|
||||
}
|
||||
|
||||
// check version
|
||||
int version = RuleBasedBreakIterator.getInt(buf, 0);
|
||||
if (version != supportedVersion) {
|
||||
throw new MissingResourceException("Dictionary version(" + version + ") is unsupported",
|
||||
dictionaryName, "");
|
||||
}
|
||||
|
||||
// get data size
|
||||
int len = RuleBasedBreakIterator.getInt(buf, 4);
|
||||
buf = new byte[len];
|
||||
if (in.read(buf) != len) {
|
||||
throw new MissingResourceException("Wrong data length",
|
||||
dictionaryName, "");
|
||||
}
|
||||
|
||||
// close the stream
|
||||
in.close();
|
||||
|
||||
int l;
|
||||
int offset = 0;
|
||||
|
||||
// read in the column map for BMP characteres (this is serialized in
|
||||
// its internal form: an index array followed by a data array)
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
short[] temp = new short[l];
|
||||
for (int i = 0; i < l; i++, offset+=2) {
|
||||
temp[i] = RuleBasedBreakIterator.getShort(buf, offset);
|
||||
}
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
byte[] temp2 = new byte[l];
|
||||
for (int i = 0; i < l; i++, offset++) {
|
||||
temp2[i] = buf[offset];
|
||||
}
|
||||
columnMap = new CompactByteArray(temp, temp2);
|
||||
|
||||
// read in numCols and numColGroups
|
||||
numCols = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
numColGroups = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
|
||||
// read in the row-number index
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
rowIndex = new short[l];
|
||||
for (int i = 0; i < l; i++, offset+=2) {
|
||||
rowIndex[i] = RuleBasedBreakIterator.getShort(buf, offset);
|
||||
}
|
||||
|
||||
// load in the populated-cells bitmap: index first, then bitmap list
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
rowIndexFlagsIndex = new short[l];
|
||||
for (int i = 0; i < l; i++, offset+=2) {
|
||||
rowIndexFlagsIndex[i] = RuleBasedBreakIterator.getShort(buf, offset);
|
||||
}
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
rowIndexFlags = new int[l];
|
||||
for (int i = 0; i < l; i++, offset+=4) {
|
||||
rowIndexFlags[i] = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
}
|
||||
|
||||
// load in the row-shift index
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
rowIndexShifts = new byte[l];
|
||||
for (int i = 0; i < l; i++, offset++) {
|
||||
rowIndexShifts[i] = buf[offset];
|
||||
}
|
||||
|
||||
// load in the actual state table
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
table = new short[l];
|
||||
for (int i = 0; i < l; i++, offset+=2) {
|
||||
table[i] = RuleBasedBreakIterator.getShort(buf, offset);
|
||||
}
|
||||
|
||||
// finally, prepare the column map for supplementary characters
|
||||
l = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
offset += 4;
|
||||
int[] temp3 = new int[l];
|
||||
for (int i = 0; i < l; i++, offset+=4) {
|
||||
temp3[i] = RuleBasedBreakIterator.getInt(buf, offset);
|
||||
}
|
||||
supplementaryCharColumnMap = new SupplementaryCharacterData(temp3);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// access to the words
|
||||
//=========================================================================
|
||||
|
||||
/**
|
||||
* Uses the column map to map the character to a column number, then
|
||||
* passes the row and column number to getNextState()
|
||||
* @param row The current state
|
||||
* @param ch The character whose column we're interested in
|
||||
* @return The new state to transition to
|
||||
*/
|
||||
public final short getNextStateFromCharacter(int row, int ch) {
|
||||
int col;
|
||||
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
col = columnMap.elementAt((char)ch);
|
||||
} else {
|
||||
col = supplementaryCharColumnMap.getValue(ch);
|
||||
}
|
||||
return getNextState(row, col);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value in the cell with the specified (logical) row and
|
||||
* column numbers. In DictionaryBasedBreakIterator, the row number is
|
||||
* a state number, the column number is an input, and the return value
|
||||
* is the row number of the new state to transition to. (0 is the
|
||||
* "error" state, and -1 is the "end of word" state in a dictionary)
|
||||
* @param row The row number of the current state
|
||||
* @param col The column number of the input character (0 means "not a
|
||||
* dictionary character")
|
||||
* @return The row number of the new state to transition to
|
||||
*/
|
||||
public final short getNextState(int row, int col) {
|
||||
if (cellIsPopulated(row, col)) {
|
||||
// we map from logical to physical row number by looking up the
|
||||
// mapping in rowIndex; we map from logical column number to
|
||||
// physical column number by looking up a shift value for this
|
||||
// logical row and offsetting the logical column number by
|
||||
// the shift amount. Then we can use internalAt() to actually
|
||||
// get the value out of the table.
|
||||
return internalAt(rowIndex[row], col + rowIndexShifts[row]);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given (logical) row and column numbers, returns true if the
|
||||
* cell in that position is populated
|
||||
*/
|
||||
private boolean cellIsPopulated(int row, int col) {
|
||||
// look up the entry in the bitmap index for the specified row.
|
||||
// If it's a negative number, it's the column number of the only
|
||||
// populated cell in the row
|
||||
if (rowIndexFlagsIndex[row] < 0) {
|
||||
return col == -rowIndexFlagsIndex[row];
|
||||
}
|
||||
|
||||
// if it's a positive number, it's the offset of an entry in the bitmap
|
||||
// list. If the table is more than 32 columns wide, the bitmap is stored
|
||||
// successive entries in the bitmap list, so we have to divide the column
|
||||
// number by 32 and offset the number we got out of the index by the result.
|
||||
// Once we have the appropriate piece of the bitmap, test the appropriate
|
||||
// bit and return the result.
|
||||
else {
|
||||
int flags = rowIndexFlags[rowIndexFlagsIndex[row] + (col >> 5)];
|
||||
return (flags & (1 << (col & 0x1f))) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of getNextState() when we know the specified cell is
|
||||
* populated.
|
||||
* @param row The PHYSICAL row number of the cell
|
||||
* @param col The PHYSICAL column number of the cell
|
||||
* @return The value stored in the cell
|
||||
*/
|
||||
private short internalAt(int row, int col) {
|
||||
// the table is a one-dimensional array, so this just does the math necessary
|
||||
// to treat it as a two-dimensional array (we don't just use a two-dimensional
|
||||
// array because two-dimensional arrays are inefficient in Java)
|
||||
return table[row * numCols + col];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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.Set;
|
||||
|
||||
/**
|
||||
* 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 dataName,
|
||||
String dictionaryName) {
|
||||
if (locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
|
||||
String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses");
|
||||
String dataFile = (String) lr.getBreakIteratorInfo(dataName);
|
||||
|
||||
try {
|
||||
switch (classNames[type]) {
|
||||
case "RuleBasedBreakIterator":
|
||||
return new RuleBasedBreakIterator(dataFile);
|
||||
case "DictionaryBasedBreakIterator":
|
||||
String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName);
|
||||
return new DictionaryBasedBreakIterator(dataFile, dictionaryFile);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid break iterator class \"" +
|
||||
classNames[type] + "\"");
|
||||
}
|
||||
} catch (IOException | MissingResourceException | IllegalArgumentException e) {
|
||||
throw new InternalError(e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAvailableLanguageTags() {
|
||||
return langtags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return LocaleProviderAdapter.isSupportedLocale(locale, type, langtags);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
208
jdkSrc/jdk8/sun/util/locale/provider/CalendarDataUtility.java
Normal file
208
jdkSrc/jdk8/sun/util/locale/provider/CalendarDataUtility.java
Normal 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 final static String FIRST_DAY_OF_WEEK = "firstDayOfWeek";
|
||||
public final static 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, 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, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, 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.CalendarNameProvider
|
||||
* CalendarNameProvider} 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 (strings != null && strings.length > 0) {
|
||||
if (field == DAY_OF_WEEK || field == YEAR) {
|
||||
--value;
|
||||
}
|
||||
if (value < 0) {
|
||||
return null;
|
||||
} else if (value >= strings.length) {
|
||||
if (field == ERA && "japanese".equals(calendarType)) {
|
||||
Era[] jeras = CalendarSystem.forName("japanese").getEras();
|
||||
if (value <= jeras.length) {
|
||||
// Localized era name could not be retrieved from this provider.
|
||||
// This can occur either for Reiwa or SupEra.
|
||||
//
|
||||
// If it's CLDR provider, try COMPAT first, which is guaranteed to have
|
||||
// the name for Reiwa.
|
||||
if (type == LocaleProviderAdapter.Type.CLDR) {
|
||||
lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
|
||||
key = getResourceKeyFor(LocaleProviderAdapter.Type.JRE,
|
||||
calendarType, field, style, javatime);
|
||||
strings =
|
||||
javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
|
||||
}
|
||||
if (strings == null || value >= strings.length) {
|
||||
// Get the default name for SupEra
|
||||
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();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
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 (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 static 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) {
|
||||
return getResourceKeyFor(this.type, type, field, style, javatime);
|
||||
}
|
||||
|
||||
private static String getResourceKeyFor(LocaleProviderAdapter.Type adapterType,
|
||||
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 (adapterType == 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 narrow day names
|
||||
if (isStandalone && isNarrow) {
|
||||
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 static String toStyleName(int baseStyle) {
|
||||
switch (baseStyle) {
|
||||
case SHORT:
|
||||
return "Abbreviations";
|
||||
case NARROW_FORMAT:
|
||||
return "Narrows";
|
||||
}
|
||||
return "Names";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.locale.provider;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Calendar.Builder;
|
||||
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;
|
||||
}
|
||||
}
|
||||
277
jdkSrc/jdk8/sun/util/locale/provider/CollationRules.java
Normal file
277
jdkSrc/jdk8/sun/util/locale/provider/CollationRules.java
Normal 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 {
|
||||
final static 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() {
|
||||
}
|
||||
}
|
||||
131
jdkSrc/jdk8/sun/util/locale/provider/CollatorProviderImpl.java
Normal file
131
jdkSrc/jdk8/sun/util/locale/provider/CollatorProviderImpl.java
Normal 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.isSupportedLocale(locale, type, 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
169
jdkSrc/jdk8/sun/util/locale/provider/DateFormatProviderImpl.java
Normal file
169
jdkSrc/jdk8/sun/util/locale/provider/DateFormatProviderImpl.java
Normal 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.isSupportedLocale(locale, type, 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;
|
||||
}
|
||||
}
|
||||
@@ -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.isSupportedLocale(locale, type, 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;
|
||||
}
|
||||
}
|
||||
@@ -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.isSupportedLocale(locale, type, 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,525 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.text.CharacterIterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* A subclass of RuleBasedBreakIterator that adds the ability to use a dictionary
|
||||
* to further subdivide ranges of text beyond what is possible using just the
|
||||
* state-table-based algorithm. This is necessary, for example, to handle
|
||||
* word and line breaking in Thai, which doesn't use spaces between words. The
|
||||
* state-table-based algorithm used by RuleBasedBreakIterator is used to divide
|
||||
* up text as far as possible, and then contiguous ranges of letters are
|
||||
* repeatedly compared against a list of known words (i.e., the dictionary)
|
||||
* to divide them up into words.
|
||||
*
|
||||
* DictionaryBasedBreakIterator uses the same rule language as RuleBasedBreakIterator,
|
||||
* but adds one more special substitution name: <dictionary>. This substitution
|
||||
* name is used to identify characters in words in the dictionary. The idea is that
|
||||
* if the iterator passes over a chunk of text that includes two or more characters
|
||||
* in a row that are included in <dictionary>, it goes back through that range and
|
||||
* derives additional break positions (if possible) using the dictionary.
|
||||
*
|
||||
* DictionaryBasedBreakIterator is also constructed with the filename of a dictionary
|
||||
* file. It follows a prescribed search path to locate the dictionary (right now,
|
||||
* it looks for it in /com/ibm/text/resources in each directory in the classpath,
|
||||
* and won't find it in JAR files, but this location is likely to change). The
|
||||
* dictionary file is in a serialized binary format. We have a very primitive (and
|
||||
* slow) BuildDictionaryFile utility for creating dictionary files, but aren't
|
||||
* currently making it public. Contact us for help.
|
||||
*/
|
||||
class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
|
||||
|
||||
/**
|
||||
* a list of known words that is used to divide up contiguous ranges of letters,
|
||||
* stored in a compressed, indexed, format that offers fast access
|
||||
*/
|
||||
private BreakDictionary dictionary;
|
||||
|
||||
/**
|
||||
* a list of flags indicating which character categories are contained in
|
||||
* the dictionary file (this is used to determine which ranges of characters
|
||||
* to apply the dictionary to)
|
||||
*/
|
||||
private boolean[] categoryFlags;
|
||||
|
||||
/**
|
||||
* a temporary hiding place for the number of dictionary characters in the
|
||||
* last range passed over by next()
|
||||
*/
|
||||
private int dictionaryCharCount;
|
||||
|
||||
/**
|
||||
* when a range of characters is divided up using the dictionary, the break
|
||||
* positions that are discovered are stored here, preventing us from having
|
||||
* to use either the dictionary or the state table again until the iterator
|
||||
* leaves this range of text
|
||||
*/
|
||||
private int[] cachedBreakPositions;
|
||||
|
||||
/**
|
||||
* if cachedBreakPositions is not null, this indicates which item in the
|
||||
* cache the current iteration position refers to
|
||||
*/
|
||||
private int positionInCache;
|
||||
|
||||
/**
|
||||
* Constructs a DictionaryBasedBreakIterator.
|
||||
* @param description Same as the description parameter on RuleBasedBreakIterator,
|
||||
* except for the special meaning of "<dictionary>". This parameter is just
|
||||
* passed through to RuleBasedBreakIterator's constructor.
|
||||
* @param dictionaryFilename The filename of the dictionary file to use
|
||||
*/
|
||||
DictionaryBasedBreakIterator(String dataFile, String dictionaryFile)
|
||||
throws IOException {
|
||||
super(dataFile);
|
||||
byte[] tmp = super.getAdditionalData();
|
||||
if (tmp != null) {
|
||||
prepareCategoryFlags(tmp);
|
||||
super.setAdditionalData(null);
|
||||
}
|
||||
dictionary = new BreakDictionary(dictionaryFile);
|
||||
}
|
||||
|
||||
private void prepareCategoryFlags(byte[] data) {
|
||||
categoryFlags = new boolean[data.length];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
categoryFlags[i] = (data[i] == (byte)1) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(CharacterIterator newText) {
|
||||
super.setText(newText);
|
||||
cachedBreakPositions = null;
|
||||
dictionaryCharCount = 0;
|
||||
positionInCache = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current iteration position to the beginning of the text.
|
||||
* (i.e., the CharacterIterator's starting offset).
|
||||
* @return The offset of the beginning of the text.
|
||||
*/
|
||||
@Override
|
||||
public int first() {
|
||||
cachedBreakPositions = null;
|
||||
dictionaryCharCount = 0;
|
||||
positionInCache = 0;
|
||||
return super.first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current iteration position to the end of the text.
|
||||
* (i.e., the CharacterIterator's ending offset).
|
||||
* @return The text's past-the-end offset.
|
||||
*/
|
||||
@Override
|
||||
public int last() {
|
||||
cachedBreakPositions = null;
|
||||
dictionaryCharCount = 0;
|
||||
positionInCache = 0;
|
||||
return super.last();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the iterator one step backwards.
|
||||
* @return The position of the last boundary position before the
|
||||
* current iteration position
|
||||
*/
|
||||
@Override
|
||||
public int previous() {
|
||||
CharacterIterator text = getText();
|
||||
|
||||
// if we have cached break positions and we're still in the range
|
||||
// covered by them, just move one step backward in the cache
|
||||
if (cachedBreakPositions != null && positionInCache > 0) {
|
||||
--positionInCache;
|
||||
text.setIndex(cachedBreakPositions[positionInCache]);
|
||||
return cachedBreakPositions[positionInCache];
|
||||
}
|
||||
|
||||
// otherwise, dump the cache and use the inherited previous() method to move
|
||||
// backward. This may fill up the cache with new break positions, in which
|
||||
// case we have to mark our position in the cache
|
||||
else {
|
||||
cachedBreakPositions = null;
|
||||
int result = super.previous();
|
||||
if (cachedBreakPositions != null) {
|
||||
positionInCache = cachedBreakPositions.length - 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current iteration position to the last boundary position
|
||||
* before the specified position.
|
||||
* @param offset The position to begin searching from
|
||||
* @return The position of the last boundary before "offset"
|
||||
*/
|
||||
@Override
|
||||
public int preceding(int offset) {
|
||||
CharacterIterator text = getText();
|
||||
checkOffset(offset, text);
|
||||
|
||||
// if we have no cached break positions, or "offset" is outside the
|
||||
// range covered by the cache, we can just call the inherited routine
|
||||
// (which will eventually call other routines in this class that may
|
||||
// refresh the cache)
|
||||
if (cachedBreakPositions == null || offset <= cachedBreakPositions[0] ||
|
||||
offset > cachedBreakPositions[cachedBreakPositions.length - 1]) {
|
||||
cachedBreakPositions = null;
|
||||
return super.preceding(offset);
|
||||
}
|
||||
|
||||
// on the other hand, if "offset" is within the range covered by the cache,
|
||||
// then all we have to do is search the cache for the last break position
|
||||
// before "offset"
|
||||
else {
|
||||
positionInCache = 0;
|
||||
while (positionInCache < cachedBreakPositions.length
|
||||
&& offset > cachedBreakPositions[positionInCache]) {
|
||||
++positionInCache;
|
||||
}
|
||||
--positionInCache;
|
||||
text.setIndex(cachedBreakPositions[positionInCache]);
|
||||
return text.getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current iteration position to the first boundary position after
|
||||
* the specified position.
|
||||
* @param offset The position to begin searching forward from
|
||||
* @return The position of the first boundary after "offset"
|
||||
*/
|
||||
@Override
|
||||
public int following(int offset) {
|
||||
CharacterIterator text = getText();
|
||||
checkOffset(offset, text);
|
||||
|
||||
// if we have no cached break positions, or if "offset" is outside the
|
||||
// range covered by the cache, then dump the cache and call our
|
||||
// inherited following() method. This will call other methods in this
|
||||
// class that may refresh the cache.
|
||||
if (cachedBreakPositions == null || offset < cachedBreakPositions[0] ||
|
||||
offset >= cachedBreakPositions[cachedBreakPositions.length - 1]) {
|
||||
cachedBreakPositions = null;
|
||||
return super.following(offset);
|
||||
}
|
||||
|
||||
// on the other hand, if "offset" is within the range covered by the
|
||||
// cache, then just search the cache for the first break position
|
||||
// after "offset"
|
||||
else {
|
||||
positionInCache = 0;
|
||||
while (positionInCache < cachedBreakPositions.length
|
||||
&& offset >= cachedBreakPositions[positionInCache]) {
|
||||
++positionInCache;
|
||||
}
|
||||
text.setIndex(cachedBreakPositions[positionInCache]);
|
||||
return text.getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the implementation function for next().
|
||||
*/
|
||||
@Override
|
||||
protected int handleNext() {
|
||||
CharacterIterator text = getText();
|
||||
|
||||
// if there are no cached break positions, or if we've just moved
|
||||
// off the end of the range covered by the cache, we have to dump
|
||||
// and possibly regenerate the cache
|
||||
if (cachedBreakPositions == null ||
|
||||
positionInCache == cachedBreakPositions.length - 1) {
|
||||
|
||||
// start by using the inherited handleNext() to find a tentative return
|
||||
// value. dictionaryCharCount tells us how many dictionary characters
|
||||
// we passed over on our way to the tentative return value
|
||||
int startPos = text.getIndex();
|
||||
dictionaryCharCount = 0;
|
||||
int result = super.handleNext();
|
||||
|
||||
// if we passed over more than one dictionary character, then we use
|
||||
// divideUpDictionaryRange() to regenerate the cached break positions
|
||||
// for the new range
|
||||
if (dictionaryCharCount > 1 && result - startPos > 1) {
|
||||
divideUpDictionaryRange(startPos, result);
|
||||
}
|
||||
|
||||
// otherwise, the value we got back from the inherited fuction
|
||||
// is our return value, and we can dump the cache
|
||||
else {
|
||||
cachedBreakPositions = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// if the cache of break positions has been regenerated (or existed all
|
||||
// along), then just advance to the next break position in the cache
|
||||
// and return it
|
||||
if (cachedBreakPositions != null) {
|
||||
++positionInCache;
|
||||
text.setIndex(cachedBreakPositions[positionInCache]);
|
||||
return cachedBreakPositions[positionInCache];
|
||||
}
|
||||
return -9999; // SHOULD NEVER GET HERE!
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a character category for a character.
|
||||
*/
|
||||
@Override
|
||||
protected int lookupCategory(int c) {
|
||||
// this override of lookupCategory() exists only to keep track of whether we've
|
||||
// passed over any dictionary characters. It calls the inherited lookupCategory()
|
||||
// to do the real work, and then checks whether its return value is one of the
|
||||
// categories represented in the dictionary. If it is, bump the dictionary-
|
||||
// character count.
|
||||
int result = super.lookupCategory(c);
|
||||
if (result != RuleBasedBreakIterator.IGNORE && categoryFlags[result]) {
|
||||
++dictionaryCharCount;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the function that actually implements the dictionary-based
|
||||
* algorithm. Given the endpoints of a range of text, it uses the
|
||||
* dictionary to determine the positions of any boundaries in this
|
||||
* range. It stores all the boundary positions it discovers in
|
||||
* cachedBreakPositions so that we only have to do this work once
|
||||
* for each time we enter the range.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void divideUpDictionaryRange(int startPos, int endPos) {
|
||||
CharacterIterator text = getText();
|
||||
|
||||
// the range we're dividing may begin or end with non-dictionary characters
|
||||
// (i.e., for line breaking, we may have leading or trailing punctuation
|
||||
// that needs to be kept with the word). Seek from the beginning of the
|
||||
// range to the first dictionary character
|
||||
text.setIndex(startPos);
|
||||
int c = getCurrent();
|
||||
int category = lookupCategory(c);
|
||||
while (category == IGNORE || !categoryFlags[category]) {
|
||||
c = getNext();
|
||||
category = lookupCategory(c);
|
||||
}
|
||||
|
||||
// initialize. We maintain two stacks: currentBreakPositions contains
|
||||
// the list of break positions that will be returned if we successfully
|
||||
// finish traversing the whole range now. possibleBreakPositions lists
|
||||
// all other possible word ends we've passed along the way. (Whenever
|
||||
// we reach an error [a sequence of characters that can't begin any word
|
||||
// in the dictionary], we back up, possibly delete some breaks from
|
||||
// currentBreakPositions, move a break from possibleBreakPositions
|
||||
// to currentBreakPositions, and start over from there. This process
|
||||
// continues in this way until we either successfully make it all the way
|
||||
// across the range, or exhaust all of our combinations of break
|
||||
// positions.)
|
||||
Stack<Integer> currentBreakPositions = new Stack<>();
|
||||
Stack<Integer> possibleBreakPositions = new Stack<>();
|
||||
List<Integer> wrongBreakPositions = new ArrayList<>();
|
||||
|
||||
// the dictionary is implemented as a trie, which is treated as a state
|
||||
// machine. -1 represents the end of a legal word. Every word in the
|
||||
// dictionary is represented by a path from the root node to -1. A path
|
||||
// that ends in state 0 is an illegal combination of characters.
|
||||
int state = 0;
|
||||
|
||||
// these two variables are used for error handling. We keep track of the
|
||||
// farthest we've gotten through the range being divided, and the combination
|
||||
// of breaks that got us that far. If we use up all possible break
|
||||
// combinations, the text contains an error or a word that's not in the
|
||||
// dictionary. In this case, we "bless" the break positions that got us the
|
||||
// farthest as real break positions, and then start over from scratch with
|
||||
// the character where the error occurred.
|
||||
int farthestEndPoint = text.getIndex();
|
||||
Stack<Integer> bestBreakPositions = null;
|
||||
|
||||
// initialize (we always exit the loop with a break statement)
|
||||
c = getCurrent();
|
||||
while (true) {
|
||||
|
||||
// if we can transition to state "-1" from our current state, we're
|
||||
// on the last character of a legal word. Push that position onto
|
||||
// the possible-break-positions stack
|
||||
if (dictionary.getNextState(state, 0) == -1) {
|
||||
possibleBreakPositions.push(text.getIndex());
|
||||
}
|
||||
|
||||
// look up the new state to transition to in the dictionary
|
||||
state = dictionary.getNextStateFromCharacter(state, c);
|
||||
|
||||
// if the character we're sitting on causes us to transition to
|
||||
// the "end of word" state, then it was a non-dictionary character
|
||||
// and we've successfully traversed the whole range. Drop out
|
||||
// of the loop.
|
||||
if (state == -1) {
|
||||
currentBreakPositions.push(text.getIndex());
|
||||
break;
|
||||
}
|
||||
|
||||
// if the character we're sitting on causes us to transition to
|
||||
// the error state, or if we've gone off the end of the range
|
||||
// without transitioning to the "end of word" state, we've hit
|
||||
// an error...
|
||||
else if (state == 0 || text.getIndex() >= endPos) {
|
||||
|
||||
// if this is the farthest we've gotten, take note of it in
|
||||
// case there's an error in the text
|
||||
if (text.getIndex() > farthestEndPoint) {
|
||||
farthestEndPoint = text.getIndex();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Stack<Integer> currentBreakPositionsCopy = (Stack<Integer>) currentBreakPositions.clone();
|
||||
|
||||
bestBreakPositions = currentBreakPositionsCopy;
|
||||
}
|
||||
|
||||
// wrongBreakPositions is a list of all break positions
|
||||
// we've tried starting that didn't allow us to traverse
|
||||
// all the way through the text. Every time we pop a
|
||||
// break position off of currentBreakPositions, we put it
|
||||
// into wrongBreakPositions to avoid trying it again later.
|
||||
// If we make it to this spot, we're either going to back
|
||||
// up to a break in possibleBreakPositions and try starting
|
||||
// over from there, or we've exhausted all possible break
|
||||
// positions and are going to do the fallback procedure.
|
||||
// This loop prevents us from messing with anything in
|
||||
// possibleBreakPositions that didn't work as a starting
|
||||
// point the last time we tried it (this is to prevent a bunch of
|
||||
// repetitive checks from slowing down some extreme cases)
|
||||
while (!possibleBreakPositions.isEmpty()
|
||||
&& wrongBreakPositions.contains(possibleBreakPositions.peek())) {
|
||||
possibleBreakPositions.pop();
|
||||
}
|
||||
|
||||
// if we've used up all possible break-position combinations, there's
|
||||
// an error or an unknown word in the text. In this case, we start
|
||||
// over, treating the farthest character we've reached as the beginning
|
||||
// of the range, and "blessing" the break positions that got us that
|
||||
// far as real break positions
|
||||
if (possibleBreakPositions.isEmpty()) {
|
||||
if (bestBreakPositions != null) {
|
||||
currentBreakPositions = bestBreakPositions;
|
||||
if (farthestEndPoint < endPos) {
|
||||
text.setIndex(farthestEndPoint + 1);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((currentBreakPositions.size() == 0 ||
|
||||
currentBreakPositions.peek().intValue() != text.getIndex())
|
||||
&& text.getIndex() != startPos) {
|
||||
currentBreakPositions.push(new Integer(text.getIndex()));
|
||||
}
|
||||
getNext();
|
||||
currentBreakPositions.push(new Integer(text.getIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
// if we still have more break positions we can try, then promote the
|
||||
// last break in possibleBreakPositions into currentBreakPositions,
|
||||
// and get rid of all entries in currentBreakPositions that come after
|
||||
// it. Then back up to that position and start over from there (i.e.,
|
||||
// treat that position as the beginning of a new word)
|
||||
else {
|
||||
Integer temp = possibleBreakPositions.pop();
|
||||
Integer temp2 = null;
|
||||
while (!currentBreakPositions.isEmpty() && temp.intValue() <
|
||||
currentBreakPositions.peek().intValue()) {
|
||||
temp2 = currentBreakPositions.pop();
|
||||
wrongBreakPositions.add(temp2);
|
||||
}
|
||||
currentBreakPositions.push(temp);
|
||||
text.setIndex(currentBreakPositions.peek().intValue());
|
||||
}
|
||||
|
||||
// re-sync "c" for the next go-round, and drop out of the loop if
|
||||
// we've made it off the end of the range
|
||||
c = getCurrent();
|
||||
if (text.getIndex() >= endPos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't hit any exceptional conditions on this last iteration,
|
||||
// just advance to the next character and loop
|
||||
else {
|
||||
c = getNext();
|
||||
}
|
||||
}
|
||||
|
||||
// dump the last break position in the list, and replace it with the actual
|
||||
// end of the range (which may be the same character, or may be further on
|
||||
// because the range actually ended with non-dictionary characters we want to
|
||||
// keep with the word)
|
||||
if (!currentBreakPositions.isEmpty()) {
|
||||
currentBreakPositions.pop();
|
||||
}
|
||||
currentBreakPositions.push(endPos);
|
||||
|
||||
// create a regular array to hold the break positions and copy
|
||||
// the break positions from the stack to the array (in addition,
|
||||
// our starting position goes into this array as a break position).
|
||||
// This array becomes the cache of break positions used by next()
|
||||
// and previous(), so this is where we actually refresh the cache.
|
||||
cachedBreakPositions = new int[currentBreakPositions.size() + 1];
|
||||
cachedBreakPositions[0] = startPos;
|
||||
|
||||
for (int i = 0; i < currentBreakPositions.size(); i++) {
|
||||
cachedBreakPositions[i + 1] = currentBreakPositions.elementAt(i).intValue();
|
||||
}
|
||||
positionInCache = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
import java.util.HashSet;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
* 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.lang.ref.SoftReference;
|
||||
import java.text.DateFormat;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.spi.DateFormatProvider;
|
||||
import java.text.spi.DateFormatSymbolsProvider;
|
||||
import java.text.spi.DecimalFormatSymbolsProvider;
|
||||
import java.text.spi.NumberFormatProvider;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Currency;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle.Control;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
import java.util.spi.CalendarDataProvider;
|
||||
import java.util.spi.CurrencyNameProvider;
|
||||
import java.util.spi.LocaleNameProvider;
|
||||
import sun.util.spi.CalendarProvider;
|
||||
|
||||
/**
|
||||
* LocaleProviderdapter implementation for the Windows locale data.
|
||||
*
|
||||
* @author Naoto Sato
|
||||
*/
|
||||
public class HostLocaleProviderAdapterImpl {
|
||||
|
||||
// locale categories
|
||||
private static final int CAT_DISPLAY = 0;
|
||||
private static final int CAT_FORMAT = 1;
|
||||
|
||||
// NumberFormat styles
|
||||
private static final int NF_NUMBER = 0;
|
||||
private static final int NF_CURRENCY = 1;
|
||||
private static final int NF_PERCENT = 2;
|
||||
private static final int NF_INTEGER = 3;
|
||||
private static final int NF_MAX = NF_INTEGER;
|
||||
|
||||
// CalendarData value types
|
||||
private static final int CD_FIRSTDAYOFWEEK = 0;
|
||||
private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
|
||||
|
||||
// Currency/Locale display name types
|
||||
private static final int DN_CURRENCY_NAME = 0;
|
||||
private static final int DN_CURRENCY_SYMBOL = 1;
|
||||
private static final int DN_LOCALE_LANGUAGE = 2;
|
||||
private static final int DN_LOCALE_SCRIPT = 3;
|
||||
private static final int DN_LOCALE_REGION = 4;
|
||||
private static final int DN_LOCALE_VARIANT = 5;
|
||||
|
||||
// Native Calendar ID to LDML calendar type map
|
||||
private static final String[] calIDToLDML = {
|
||||
"",
|
||||
"gregory",
|
||||
"gregory_en-US",
|
||||
"japanese",
|
||||
"roc",
|
||||
"", // No appropriate type for CAL_KOREA
|
||||
"islamic",
|
||||
"buddhist",
|
||||
"hebrew",
|
||||
"gregory_fr",
|
||||
"gregory_ar",
|
||||
"gregory_en",
|
||||
"gregory_fr",
|
||||
};
|
||||
|
||||
// Caches
|
||||
private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
|
||||
private static ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
|
||||
private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
|
||||
private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Set<Locale> supportedLocaleSet;
|
||||
private static final String nativeDisplayLanguage;
|
||||
static {
|
||||
Set<Locale> tmpSet = new HashSet<>();
|
||||
if (initialize()) {
|
||||
// Assuming the default locales do not include any extensions, so
|
||||
// no stripping is needed here.
|
||||
Control c = Control.getNoFallbackControl(Control.FORMAT_DEFAULT);
|
||||
String displayLocale = getDefaultLocale(CAT_DISPLAY);
|
||||
Locale l = Locale.forLanguageTag(displayLocale.replace('_', '-'));
|
||||
tmpSet.addAll(c.getCandidateLocales("", l));
|
||||
nativeDisplayLanguage = l.getLanguage();
|
||||
|
||||
String formatLocale = getDefaultLocale(CAT_FORMAT);
|
||||
if (!formatLocale.equals(displayLocale)) {
|
||||
l = Locale.forLanguageTag(formatLocale.replace('_', '-'));
|
||||
tmpSet.addAll(c.getCandidateLocales("", l));
|
||||
}
|
||||
} else {
|
||||
nativeDisplayLanguage = "";
|
||||
}
|
||||
supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
|
||||
}
|
||||
private final static Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
|
||||
|
||||
public static DateFormatProvider getDateFormatProvider() {
|
||||
return new DateFormatProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormat getDateInstance(int style, Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
|
||||
return new SimpleDateFormat(patterns.get(style/2),
|
||||
getCalendarLocale(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormat getTimeInstance(int style, Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
|
||||
return new SimpleDateFormat(patterns.get(style/2+2),
|
||||
getCalendarLocale(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormat getDateTimeInstance(int dateStyle,
|
||||
int timeStyle, Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
|
||||
String pattern = new StringBuilder(patterns.get(dateStyle/2))
|
||||
.append(" ")
|
||||
.append(patterns.get(timeStyle/2+2))
|
||||
.toString();
|
||||
return new SimpleDateFormat(pattern, getCalendarLocale(locale));
|
||||
}
|
||||
|
||||
private AtomicReferenceArray<String> getDateTimePatterns(Locale locale) {
|
||||
AtomicReferenceArray<String> patterns;
|
||||
SoftReference<AtomicReferenceArray<String>> ref = dateFormatCache.get(locale);
|
||||
|
||||
if (ref == null || (patterns = ref.get()) == null) {
|
||||
String langtag = removeExtensions(locale).toLanguageTag();
|
||||
patterns = new AtomicReferenceArray<>(4);
|
||||
patterns.compareAndSet(0, null, convertDateTimePattern(
|
||||
getDateTimePattern(DateFormat.LONG, -1, langtag)));
|
||||
patterns.compareAndSet(1, null, convertDateTimePattern(
|
||||
getDateTimePattern(DateFormat.SHORT, -1, langtag)));
|
||||
patterns.compareAndSet(2, null, convertDateTimePattern(
|
||||
getDateTimePattern(-1, DateFormat.LONG, langtag)));
|
||||
patterns.compareAndSet(3, null, convertDateTimePattern(
|
||||
getDateTimePattern(-1, DateFormat.SHORT, langtag)));
|
||||
ref = new SoftReference<>(patterns);
|
||||
dateFormatCache.put(locale, ref);
|
||||
}
|
||||
|
||||
return patterns;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
|
||||
return new DateFormatSymbolsProvider() {
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormatSymbols getInstance(Locale locale) {
|
||||
DateFormatSymbols dfs;
|
||||
SoftReference<DateFormatSymbols> ref =
|
||||
dateFormatSymbolsCache.get(locale);
|
||||
|
||||
if (ref == null || (dfs = ref.get()) == null) {
|
||||
dfs = new DateFormatSymbols(locale);
|
||||
String langTag = removeExtensions(locale).toLanguageTag();
|
||||
|
||||
dfs.setAmPmStrings(getAmPmStrings(langTag, dfs.getAmPmStrings()));
|
||||
dfs.setEras(getEras(langTag, dfs.getEras()));
|
||||
dfs.setMonths(getMonths(langTag, dfs.getMonths()));
|
||||
dfs.setShortMonths(getShortMonths(langTag, dfs.getShortMonths()));
|
||||
dfs.setWeekdays(getWeekdays(langTag, dfs.getWeekdays()));
|
||||
dfs.setShortWeekdays(getShortWeekdays(langTag, dfs.getShortWeekdays()));
|
||||
ref = new SoftReference<>(dfs);
|
||||
dateFormatSymbolsCache.put(locale, ref);
|
||||
}
|
||||
return (DateFormatSymbols)dfs.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static NumberFormatProvider getNumberFormatProvider() {
|
||||
return new NumberFormatProvider() {
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedNativeDigitLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedNativeDigitLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getCurrencyInstance(Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
|
||||
return new DecimalFormat(patterns.get(NF_CURRENCY),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getIntegerInstance(Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
|
||||
return new DecimalFormat(patterns.get(NF_INTEGER),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getNumberInstance(Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
|
||||
return new DecimalFormat(patterns.get(NF_NUMBER),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormat getPercentInstance(Locale locale) {
|
||||
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
|
||||
return new DecimalFormat(patterns.get(NF_PERCENT),
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
|
||||
private AtomicReferenceArray<String> getNumberPatterns(Locale locale) {
|
||||
AtomicReferenceArray<String> patterns;
|
||||
SoftReference<AtomicReferenceArray<String>> ref = numberFormatCache.get(locale);
|
||||
|
||||
if (ref == null || (patterns = ref.get()) == null) {
|
||||
String langtag = locale.toLanguageTag();
|
||||
patterns = new AtomicReferenceArray<>(NF_MAX+1);
|
||||
for (int i = 0; i <= NF_MAX; i++) {
|
||||
patterns.compareAndSet(i, null, getNumberPattern(i, langtag));
|
||||
}
|
||||
ref = new SoftReference<>(patterns);
|
||||
numberFormatCache.put(locale, ref);
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
|
||||
return new DecimalFormatSymbolsProvider() {
|
||||
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedNativeDigitLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedNativeDigitLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalFormatSymbols getInstance(Locale locale) {
|
||||
DecimalFormatSymbols dfs;
|
||||
SoftReference<DecimalFormatSymbols> ref =
|
||||
decimalFormatSymbolsCache.get(locale);
|
||||
|
||||
if (ref == null || (dfs = ref.get()) == null) {
|
||||
dfs = new DecimalFormatSymbols(getNumberLocale(locale));
|
||||
String langTag = removeExtensions(locale).toLanguageTag();
|
||||
|
||||
// DecimalFormatSymbols.setInternationalCurrencySymbol() has
|
||||
// a side effect of setting the currency symbol as well. So
|
||||
// the calling order is relevant here.
|
||||
dfs.setInternationalCurrencySymbol(getInternationalCurrencySymbol(langTag, dfs.getInternationalCurrencySymbol()));
|
||||
dfs.setCurrencySymbol(getCurrencySymbol(langTag, dfs.getCurrencySymbol()));
|
||||
dfs.setDecimalSeparator(getDecimalSeparator(langTag, dfs.getDecimalSeparator()));
|
||||
dfs.setGroupingSeparator(getGroupingSeparator(langTag, dfs.getGroupingSeparator()));
|
||||
dfs.setInfinity(getInfinity(langTag, dfs.getInfinity()));
|
||||
dfs.setMinusSign(getMinusSign(langTag, dfs.getMinusSign()));
|
||||
dfs.setMonetaryDecimalSeparator(getMonetaryDecimalSeparator(langTag, dfs.getMonetaryDecimalSeparator()));
|
||||
dfs.setNaN(getNaN(langTag, dfs.getNaN()));
|
||||
dfs.setPercent(getPercent(langTag, dfs.getPercent()));
|
||||
dfs.setPerMill(getPerMill(langTag, dfs.getPerMill()));
|
||||
dfs.setZeroDigit(getZeroDigit(langTag, dfs.getZeroDigit()));
|
||||
ref = new SoftReference<>(dfs);
|
||||
decimalFormatSymbolsCache.put(locale, ref);
|
||||
}
|
||||
return (DecimalFormatSymbols)dfs.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CalendarDataProvider getCalendarDataProvider() {
|
||||
return new CalendarDataProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstDayOfWeek(Locale locale) {
|
||||
int first = getCalendarDataValue(
|
||||
removeExtensions(locale).toLanguageTag(),
|
||||
CD_FIRSTDAYOFWEEK);
|
||||
if (first != -1) {
|
||||
return (first + 1) % 7 + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimalDaysInFirstWeek(Locale locale) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CalendarProvider getCalendarProvider() {
|
||||
return new CalendarProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return getSupportedCalendarLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return isSupportedCalendarLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getInstance(TimeZone zone, Locale locale) {
|
||||
return new Calendar.Builder()
|
||||
.setLocale(getCalendarLocale(locale))
|
||||
.setTimeZone(zone)
|
||||
.setInstant(System.currentTimeMillis())
|
||||
.build();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static CurrencyNameProvider getCurrencyNameProvider() {
|
||||
return new CurrencyNameProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
// Ignore the extensions for now
|
||||
return supportedLocaleSet.contains(locale.stripExtensions()) &&
|
||||
locale.getLanguage().equals(nativeDisplayLanguage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbol(String currencyCode, Locale locale) {
|
||||
// Retrieves the currency symbol by calling
|
||||
// GetLocaleInfoEx(LOCALE_SCURRENCY).
|
||||
// It only works with the "locale"'s currency in its native
|
||||
// language.
|
||||
try {
|
||||
if (Currency.getInstance(locale).getCurrencyCode()
|
||||
.equals(currencyCode)) {
|
||||
return getDisplayString(locale.toLanguageTag(),
|
||||
DN_CURRENCY_SYMBOL, currencyCode);
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(String currencyCode, Locale locale) {
|
||||
// Retrieves the display name by calling
|
||||
// GetLocaleInfoEx(LOCALE_SNATIVECURRNAME).
|
||||
// It only works with the "locale"'s currency in its native
|
||||
// language.
|
||||
try {
|
||||
if (Currency.getInstance(locale).getCurrencyCode()
|
||||
.equals(currencyCode)) {
|
||||
return getDisplayString(locale.toLanguageTag(),
|
||||
DN_CURRENCY_NAME, currencyCode);
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static LocaleNameProvider getLocaleNameProvider() {
|
||||
return new LocaleNameProvider() {
|
||||
@Override
|
||||
public Locale[] getAvailableLocales() {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedLocale(Locale locale) {
|
||||
return supportedLocaleSet.contains(locale.stripExtensions()) &&
|
||||
locale.getLanguage().equals(nativeDisplayLanguage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayLanguage(String languageCode, Locale locale) {
|
||||
// Retrieves the display language name by calling
|
||||
// GetLocaleInfoEx(LOCALE_SLOCALIZEDLANGUAGENAME).
|
||||
return getDisplayString(locale.toLanguageTag(),
|
||||
DN_LOCALE_LANGUAGE, languageCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCountry(String countryCode, Locale locale) {
|
||||
// Retrieves the display country name by calling
|
||||
// GetLocaleInfoEx(LOCALE_SLOCALIZEDCOUNTRYNAME).
|
||||
return getDisplayString(locale.toLanguageTag(),
|
||||
DN_LOCALE_REGION, nativeDisplayLanguage+"-"+countryCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayScript(String scriptCode, Locale locale) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayVariant(String variantCode, Locale locale) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static String convertDateTimePattern(String winPattern) {
|
||||
String ret = winPattern.replaceAll("dddd", "EEEE");
|
||||
ret = ret.replaceAll("ddd", "EEE");
|
||||
ret = ret.replaceAll("tt", "aa");
|
||||
ret = ret.replaceAll("g", "GG");
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static Locale[] getSupportedCalendarLocales() {
|
||||
if (supportedLocale.length != 0 &&
|
||||
supportedLocaleSet.contains(Locale.JAPAN) &&
|
||||
isJapaneseCalendar()) {
|
||||
Locale[] sup = new Locale[supportedLocale.length+1];
|
||||
sup[0] = JRELocaleConstants.JA_JP_JP;
|
||||
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
|
||||
return sup;
|
||||
}
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
private static boolean isSupportedCalendarLocale(Locale locale) {
|
||||
Locale base = locale;
|
||||
|
||||
if (base.hasExtensions() || base.getVariant() != "") {
|
||||
// strip off extensions and variant.
|
||||
base = new Locale.Builder()
|
||||
.setLocale(locale)
|
||||
.clearExtensions()
|
||||
.build();
|
||||
}
|
||||
|
||||
if (!supportedLocaleSet.contains(base)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int calid = getCalendarID(base.toLanguageTag());
|
||||
if (calid <= 0 || calid >= calIDToLDML.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String requestedCalType = locale.getUnicodeLocaleType("ca");
|
||||
String nativeCalType = calIDToLDML[calid]
|
||||
.replaceFirst("_.*", ""); // remove locale part.
|
||||
|
||||
if (requestedCalType == null) {
|
||||
return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
|
||||
} else {
|
||||
return requestedCalType.equals(nativeCalType);
|
||||
}
|
||||
}
|
||||
|
||||
private static Locale[] getSupportedNativeDigitLocales() {
|
||||
if (supportedLocale.length != 0 &&
|
||||
supportedLocaleSet.contains(JRELocaleConstants.TH_TH) &&
|
||||
isNativeDigit("th-TH")) {
|
||||
Locale[] sup = new Locale[supportedLocale.length+1];
|
||||
sup[0] = JRELocaleConstants.TH_TH_TH;
|
||||
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
|
||||
return sup;
|
||||
}
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
private static boolean isSupportedNativeDigitLocale(Locale locale) {
|
||||
// special case for th_TH_TH
|
||||
if (JRELocaleConstants.TH_TH_TH.equals(locale)) {
|
||||
return isNativeDigit("th-TH");
|
||||
}
|
||||
|
||||
String numtype = null;
|
||||
Locale base = locale;
|
||||
if (locale.hasExtensions()) {
|
||||
numtype = locale.getUnicodeLocaleType("nu");
|
||||
base = locale.stripExtensions();
|
||||
}
|
||||
|
||||
if (supportedLocaleSet.contains(base)) {
|
||||
// Only supports Latin or Thai (in thai locales) digits.
|
||||
if (numtype == null || numtype.equals("latn")) {
|
||||
return true;
|
||||
} else if (locale.getLanguage().equals("th")) {
|
||||
return "thai".equals(numtype) &&
|
||||
isNativeDigit(locale.toLanguageTag());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Locale removeExtensions(Locale src) {
|
||||
return new Locale.Builder().setLocale(src).clearExtensions().build();
|
||||
}
|
||||
|
||||
private static boolean isJapaneseCalendar() {
|
||||
return getCalendarID("ja-JP") == 3; // 3: CAL_JAPAN
|
||||
}
|
||||
|
||||
private static Locale getCalendarLocale(Locale locale) {
|
||||
int calid = getCalendarID(locale.toLanguageTag());
|
||||
if (calid > 0 && calid < calIDToLDML.length) {
|
||||
Locale.Builder lb = new Locale.Builder();
|
||||
String[] caltype = calIDToLDML[calid].split("_");
|
||||
if (caltype.length > 1) {
|
||||
lb.setLocale(Locale.forLanguageTag(caltype[1]));
|
||||
} else {
|
||||
lb.setLocale(locale);
|
||||
}
|
||||
lb.setUnicodeLocaleKeyword("ca", caltype[0]);
|
||||
return lb.build();
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
private static Locale getNumberLocale(Locale src) {
|
||||
if (JRELocaleConstants.TH_TH.equals(src)) {
|
||||
if (isNativeDigit("th-TH")) {
|
||||
Locale.Builder lb = new Locale.Builder().setLocale(src);
|
||||
lb.setUnicodeLocaleKeyword("nu", "thai");
|
||||
return lb.build();
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
// native methods
|
||||
|
||||
// initialize
|
||||
private static native boolean initialize();
|
||||
private static native String getDefaultLocale(int cat);
|
||||
|
||||
// For DateFormatProvider
|
||||
private static native String getDateTimePattern(int dateStyle, int timeStyle, String langTag);
|
||||
private static native int getCalendarID(String langTag);
|
||||
|
||||
// For DateFormatSymbolsProvider
|
||||
private static native String[] getAmPmStrings(String langTag, String[] ampm);
|
||||
private static native String[] getEras(String langTag, String[] eras);
|
||||
private static native String[] getMonths(String langTag, String[] months);
|
||||
private static native String[] getShortMonths(String langTag, String[] smonths);
|
||||
private static native String[] getWeekdays(String langTag, String[] wdays);
|
||||
private static native String[] getShortWeekdays(String langTag, String[] swdays);
|
||||
|
||||
// For NumberFormatProvider
|
||||
private static native String getNumberPattern(int numberStyle, String langTag);
|
||||
private static native boolean isNativeDigit(String langTag);
|
||||
|
||||
// For DecimalFormatSymbolsProvider
|
||||
private static native String getCurrencySymbol(String langTag, String currencySymbol);
|
||||
private static native char getDecimalSeparator(String langTag, char decimalSeparator);
|
||||
private static native char getGroupingSeparator(String langTag, char groupingSeparator);
|
||||
private static native String getInfinity(String langTag, String infinity);
|
||||
private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
|
||||
private static native char getMinusSign(String langTag, char minusSign);
|
||||
private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
|
||||
private static native String getNaN(String langTag, String nan);
|
||||
private static native char getPercent(String langTag, char percent);
|
||||
private static native char getPerMill(String langTag, char perMill);
|
||||
private static native char getZeroDigit(String langTag, char zeroDigit);
|
||||
|
||||
// For CalendarDataProvider
|
||||
private static native int getCalendarDataValue(String langTag, int type);
|
||||
|
||||
// For Locale/CurrencyNameProvider
|
||||
private static native String getDisplayString(String langTag, int key, String value);
|
||||
}
|
||||
45
jdkSrc/jdk8/sun/util/locale/provider/JRELocaleConstants.java
Normal file
45
jdkSrc/jdk8/sun/util/locale/provider/JRELocaleConstants.java
Normal 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() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* 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.io.File;
|
||||
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.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
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.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 static final String LOCALE_DATA_JAR_NAME = "localedata.jar";
|
||||
|
||||
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();
|
||||
default:
|
||||
throw new InternalError("should not come down here");
|
||||
}
|
||||
}
|
||||
|
||||
private volatile BreakIteratorProvider breakIteratorProvider = null;
|
||||
private volatile CollatorProvider collatorProvider = null;
|
||||
private volatile DateFormatProvider dateFormatProvider = null;
|
||||
private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider = null;
|
||||
private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider = null;
|
||||
private volatile NumberFormatProvider numberFormatProvider = null;
|
||||
|
||||
private volatile CurrencyNameProvider currencyNameProvider = null;
|
||||
private volatile LocaleNameProvider localeNameProvider = null;
|
||||
private volatile TimeZoneNameProvider timeZoneNameProvider = null;
|
||||
private volatile CalendarDataProvider calendarDataProvider = null;
|
||||
private volatile CalendarNameProvider calendarNameProvider = null;
|
||||
|
||||
private volatile CalendarProvider calendarProvider = null;
|
||||
|
||||
/*
|
||||
* Getter methods for java.text.spi.* providers
|
||||
*/
|
||||
@Override
|
||||
public BreakIteratorProvider getBreakIteratorProvider() {
|
||||
if (breakIteratorProvider == null) {
|
||||
BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("FormatData"));
|
||||
synchronized (this) {
|
||||
if (breakIteratorProvider == null) {
|
||||
breakIteratorProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return breakIteratorProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollatorProvider getCollatorProvider() {
|
||||
if (collatorProvider == null) {
|
||||
CollatorProvider provider = new CollatorProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("CollationData"));
|
||||
synchronized (this) {
|
||||
if (collatorProvider == null) {
|
||||
collatorProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return collatorProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormatProvider getDateFormatProvider() {
|
||||
if (dateFormatProvider == null) {
|
||||
DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("FormatData"));
|
||||
synchronized (this) {
|
||||
if (dateFormatProvider == null) {
|
||||
dateFormatProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dateFormatProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
|
||||
if (dateFormatSymbolsProvider == null) {
|
||||
DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("FormatData"));
|
||||
synchronized (this) {
|
||||
if (dateFormatSymbolsProvider == null) {
|
||||
dateFormatSymbolsProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dateFormatSymbolsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
|
||||
if (decimalFormatSymbolsProvider == null) {
|
||||
DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType(), getLanguageTagSet("FormatData"));
|
||||
synchronized (this) {
|
||||
if (decimalFormatSymbolsProvider == null) {
|
||||
decimalFormatSymbolsProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return decimalFormatSymbolsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberFormatProvider getNumberFormatProvider() {
|
||||
if (numberFormatProvider == null) {
|
||||
NumberFormatProvider provider = 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 = new CurrencyNameProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("CurrencyNames"));
|
||||
synchronized (this) {
|
||||
if (currencyNameProvider == null) {
|
||||
currencyNameProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return currencyNameProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleNameProvider getLocaleNameProvider() {
|
||||
if (localeNameProvider == null) {
|
||||
LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("LocaleNames"));
|
||||
synchronized (this) {
|
||||
if (localeNameProvider == null) {
|
||||
localeNameProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return localeNameProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZoneNameProvider getTimeZoneNameProvider() {
|
||||
if (timeZoneNameProvider == null) {
|
||||
TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("TimeZoneNames"));
|
||||
synchronized (this) {
|
||||
if (timeZoneNameProvider == null) {
|
||||
timeZoneNameProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return timeZoneNameProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarDataProvider getCalendarDataProvider() {
|
||||
if (calendarDataProvider == null) {
|
||||
CalendarDataProvider provider;
|
||||
provider = new CalendarDataProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("CalendarData"));
|
||||
synchronized (this) {
|
||||
if (calendarDataProvider == null) {
|
||||
calendarDataProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return calendarDataProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarNameProvider getCalendarNameProvider() {
|
||||
if (calendarNameProvider == null) {
|
||||
CalendarNameProvider provider;
|
||||
provider = 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 = new CalendarProviderImpl(getAdapterType(),
|
||||
getLanguageTagSet("CalendarData"));
|
||||
synchronized (this) {
|
||||
if (calendarProvider == null) {
|
||||
calendarProvider = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
return calendarProvider;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = LocaleDataMetaInfo.getSupportedLocaleString(category);
|
||||
if (supportedLocaleString == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> tagset = new HashSet<>();
|
||||
StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
|
||||
while (tokens.hasMoreTokens()) {
|
||||
String token = tokens.nextToken();
|
||||
if (token.equals("|")) {
|
||||
if (isNonENLangSupported()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tagset.add(token);
|
||||
}
|
||||
|
||||
return tagset;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class and then
|
||||
* contructs the Locale array and a set of language tags based on the
|
||||
* locale string returned above.
|
||||
*/
|
||||
String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString("AvailableLocales");
|
||||
|
||||
if (supportedLocaleString.length() == 0) {
|
||||
throw new InternalError("No available locales for JRE");
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for "|" and construct a new locale string list.
|
||||
*/
|
||||
int barIndex = supportedLocaleString.indexOf('|');
|
||||
StringTokenizer localeStringTokenizer;
|
||||
if (isNonENLangSupported()) {
|
||||
localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)
|
||||
+ supportedLocaleString.substring(barIndex + 1));
|
||||
} else {
|
||||
localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static volatile Boolean isNonENSupported = null;
|
||||
|
||||
/*
|
||||
* Returns true if the non EN resources jar file exists in jre
|
||||
* extension directory. @returns true if the jar file is there. Otherwise,
|
||||
* returns false.
|
||||
*/
|
||||
private static boolean isNonENLangSupported() {
|
||||
if (isNonENSupported == null) {
|
||||
synchronized (JRELocaleProviderAdapter.class) {
|
||||
if (isNonENSupported == null) {
|
||||
final String sep = File.separator;
|
||||
String localeDataJar =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("java.home"))
|
||||
+ sep + "lib" + sep + "ext" + sep + LOCALE_DATA_JAR_NAME;
|
||||
|
||||
/*
|
||||
* Peek at the installed extension directory to see if
|
||||
* localedata.jar is installed or not.
|
||||
*/
|
||||
final File f = new File(localeDataJar);
|
||||
isNonENSupported =
|
||||
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return f.exists();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return isNonENSupported;
|
||||
}
|
||||
}
|
||||
89
jdkSrc/jdk8/sun/util/locale/provider/LocaleDataMetaInfo.java
Normal file
89
jdkSrc/jdk8/sun/util/locale/provider/LocaleDataMetaInfo.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
package sun.util.locale.provider;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class LocaleDataMetaInfo {
|
||||
|
||||
private static final HashMap<String, String> resourceNameToLocales =
|
||||
new HashMap<String, String>(7);
|
||||
|
||||
|
||||
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",
|
||||
" en en-AU en-CA en-GB en-IE en-IN en-MT en-NZ en-PH en-SG en-US en-ZA | ar ar-JO ar-LB ar-SY be be-BY bg bg-BG ca ca-ES cs cs-CZ da da-DK de de-AT de-CH de-DE de-LU el el-CY el-GR es es-AR es-BO es-CL es-CO es-CR es-DO es-EC es-ES es-GT es-HN es-MX es-NI es-PA es-PE es-PR es-PY es-SV es-US es-UY es-VE et et-EE fi fi-FI fr fr-BE fr-CA fr-CH fr-FR ga ga-IE hi-IN hr hr-HR hu hu-HU in in-ID is is-IS it it-CH it-IT iw iw-IL ja ja-JP ko ko-KR lt lt-LT lv lv-LV mk mk-MK ms ms-MY mt mt-MT nl nl-BE nl-NL no no-NO no-NO-NY pl pl-PL pt pt-BR pt-PT ro ro-RO ru ru-RU sk sk-SK sl sl-SI sq sq-AL sr sr-BA sr-CS sr-Latn sr-Latn-ME sr-ME sr-RS sv sv-SE th th-TH tr tr-TR uk uk-UA vi vi-VN zh zh-CN zh-HK zh-SG zh-TW ");
|
||||
|
||||
resourceNameToLocales.put("CollationData",
|
||||
" | ar be bg ca cs da el es et fi fr hi hr hu is iw ja ko lt lv mk no pl ro ru sk sl sq sr sr-Latn sv th tr uk vi zh zh-HK zh-TW ");
|
||||
|
||||
resourceNameToLocales.put("BreakIteratorInfo",
|
||||
" | th ");
|
||||
|
||||
resourceNameToLocales.put("BreakIteratorRules",
|
||||
" | th ");
|
||||
|
||||
resourceNameToLocales.put("TimeZoneNames",
|
||||
" en en-CA en-GB en-IE | de es fr hi it ja ko pt-BR sv zh-CN zh-HK zh-TW ");
|
||||
|
||||
resourceNameToLocales.put("LocaleNames",
|
||||
" en en-MT en-PH en-SG | ar be bg ca cs da de el el-CY es es-US et fi fr ga hi hr hu in is it iw ja ko lt lv mk ms mt nl no no-NO-NY pl pt pt-PT ro ru sk sl sq sr sr-Latn sv th tr uk vi zh zh-HK zh-SG zh-TW ");
|
||||
|
||||
resourceNameToLocales.put("CurrencyNames",
|
||||
" en-AU en-CA en-GB en-IE en-IN en-MT en-NZ en-PH en-SG en-US en-ZA | ar-AE ar-BH ar-DZ ar-EG ar-IQ ar-JO ar-KW ar-LB ar-LY ar-MA ar-OM ar-QA ar-SA ar-SD ar-SY ar-TN ar-YE be-BY bg-BG ca-ES cs-CZ da-DK de de-AT de-CH de-DE de-GR de-LU el-CY el-GR es es-AR es-BO es-CL es-CO es-CR es-CU es-DO es-EC es-ES es-GT es-HN es-MX es-NI es-PA es-PE es-PR es-PY es-SV es-US es-UY es-VE et-EE fi-FI fr fr-BE fr-CA fr-CH fr-FR fr-LU ga-IE hi-IN hr-HR hu-HU in-ID is-IS it it-CH it-IT iw-IL ja ja-JP ko ko-KR lt-LT lv-LV mk-MK ms-MY mt-MT nl-BE nl-NL no-NO pl-PL pt pt-BR pt-PT ro-RO ru-RU sk-SK sl-SI sq-AL sr-BA sr-CS sr-Latn-BA sr-Latn-ME sr-Latn-RS sr-ME sr-RS sv sv-SE th-TH tr-TR uk-UA vi-VN zh-CN zh-HK zh-SG zh-TW ");
|
||||
|
||||
resourceNameToLocales.put("CalendarData",
|
||||
" en en-GB en-IE en-MT | ar be bg ca cs da de el el-CY es es-ES es-US et fi fr fr-CA hi hr hu in-ID is it iw ja ko lt lv mk ms-MY mt mt-MT nl no pl pt pt-BR pt-PT ro ru sk sl sq sr sr-Latn-BA sr-Latn-ME sr-Latn-RS sv th tr uk vi zh ");
|
||||
|
||||
resourceNameToLocales.put("AvailableLocales",
|
||||
" en en-AU en-CA en-GB en-IE en-IN en-MT en-NZ en-PH en-SG en-US en-ZA | ar ar-AE ar-BH ar-DZ ar-EG ar-IQ ar-JO ar-KW ar-LB ar-LY ar-MA ar-OM ar-QA ar-SA ar-SD ar-SY ar-TN ar-YE be be-BY bg bg-BG ca ca-ES cs cs-CZ da da-DK de de-AT de-CH de-DE de-GR de-LU el el-CY el-GR es es-AR es-BO es-CL es-CO es-CR es-CU es-DO es-EC es-ES es-GT es-HN es-MX es-NI es-PA es-PE es-PR es-PY es-SV es-US es-UY es-VE et et-EE fi fi-FI fr fr-BE fr-CA fr-CH fr-FR fr-LU ga ga-IE hi hi-IN hr hr-HR hu hu-HU in in-ID is is-IS it it-CH it-IT iw iw-IL ja ja-JP ja-JP-JP ko ko-KR lt lt-LT lv lv-LV mk mk-MK ms ms-MY mt mt-MT nl nl-BE nl-NL no no-NO no-NO-NY pl pl-PL pt pt-BR pt-PT ro ro-RO ru ru-RU sk sk-SK sl sl-SI sq sq-AL sr sr-BA sr-CS sr-Latn sr-Latn-BA sr-Latn-ME sr-Latn-RS sr-ME sr-RS sv sv-SE th th-TH th-TH-TH tr tr-TR uk uk-UA vi vi-VN zh zh-CN zh-HK zh-SG zh-TW ");
|
||||
}
|
||||
|
||||
/*
|
||||
* @param resourceName the resource name
|
||||
* @return the supported locale string for the passed in resource.
|
||||
*/
|
||||
public static String getSupportedLocaleString(String resourceName) {
|
||||
return resourceNameToLocales.get(resourceName);
|
||||
}
|
||||
}
|
||||
183
jdkSrc/jdk8/sun/util/locale/provider/LocaleNameProviderImpl.java
Normal file
183
jdkSrc/jdk8/sun/util/locale/provider/LocaleNameProviderImpl.java
Normal 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.isSupportedLocale(locale, type, 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 languageCode 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 countryCode 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 variant 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;
|
||||
}
|
||||
}
|
||||
456
jdkSrc/jdk8/sun/util/locale/provider/LocaleProviderAdapter.java
Normal file
456
jdkSrc/jdk8/sun/util/locale/provider/LocaleProviderAdapter.java
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* 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.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.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.util.cldr.CLDRLocaleProviderAdapter;
|
||||
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.resources", "sun.text.resources"),
|
||||
CLDR("sun.util.resources.cldr", "sun.text.resources.cldr"),
|
||||
SPI,
|
||||
HOST,
|
||||
FALLBACK("sun.util.resources", "sun.text.resources");
|
||||
|
||||
private final String UTIL_RESOURCES_PACKAGE;
|
||||
private final String TEXT_RESOURCES_PACKAGE;
|
||||
|
||||
private Type() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
private Type(String util, String text) {
|
||||
UTIL_RESOURCES_PACKAGE = util;
|
||||
TEXT_RESOURCES_PACKAGE = text;
|
||||
}
|
||||
|
||||
public String getUtilResourcesPackage() {
|
||||
return UTIL_RESOURCES_PACKAGE;
|
||||
}
|
||||
|
||||
public String getTextResourcesPackage() {
|
||||
return TEXT_RESOURCES_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LocaleProviderAdapter preference list. The default list is intended
|
||||
* to behave the same manner in JDK7.
|
||||
*/
|
||||
private static final List<Type> adapterPreference;
|
||||
|
||||
/**
|
||||
* JRE Locale Data Adapter instance
|
||||
*/
|
||||
private static LocaleProviderAdapter jreLocaleProviderAdapter = new JRELocaleProviderAdapter();
|
||||
|
||||
/**
|
||||
* SPI Locale Data Adapter instance
|
||||
*/
|
||||
private static LocaleProviderAdapter spiLocaleProviderAdapter = new SPILocaleProviderAdapter();
|
||||
|
||||
/**
|
||||
* CLDR Locale Data Adapter instance, if any.
|
||||
*/
|
||||
private static LocaleProviderAdapter cldrLocaleProviderAdapter = null;
|
||||
|
||||
/**
|
||||
* HOST Locale Data Adapter instance, if any.
|
||||
*/
|
||||
private static LocaleProviderAdapter hostLocaleProviderAdapter = null;
|
||||
|
||||
/**
|
||||
* FALLBACK Locale Data Adapter instance. It's basically the same with JRE, but only kicks
|
||||
* in for the root locale.
|
||||
*/
|
||||
private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null;
|
||||
|
||||
/**
|
||||
* Default fallback adapter type, which should return something meaningful in any case.
|
||||
* This is either JRE or FALLBACK.
|
||||
*/
|
||||
static LocaleProviderAdapter.Type defaultLocaleProviderAdapter = null;
|
||||
|
||||
/**
|
||||
* Adapter lookup cache.
|
||||
*/
|
||||
private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>>
|
||||
adapterCache = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
String order = AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("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) {
|
||||
try {
|
||||
Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT));
|
||||
|
||||
// load adapter if necessary
|
||||
switch (aType) {
|
||||
case CLDR:
|
||||
if (cldrLocaleProviderAdapter == null) {
|
||||
cldrLocaleProviderAdapter = new CLDRLocaleProviderAdapter();
|
||||
}
|
||||
break;
|
||||
case HOST:
|
||||
if (hostLocaleProviderAdapter == null) {
|
||||
hostLocaleProviderAdapter = new HostLocaleProviderAdapter();
|
||||
}
|
||||
break;
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeList.isEmpty()) {
|
||||
if (!typeList.contains(Type.JRE)) {
|
||||
// Append FALLBACK as the last resort.
|
||||
fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter();
|
||||
typeList.add(Type.FALLBACK);
|
||||
defaultLocaleProviderAdapter = Type.FALLBACK;
|
||||
} else {
|
||||
defaultLocaleProviderAdapter = Type.JRE;
|
||||
}
|
||||
} else {
|
||||
// Default preference list
|
||||
typeList.add(Type.JRE);
|
||||
typeList.add(Type.SPI);
|
||||
defaultLocaleProviderAdapter = Type.JRE;
|
||||
}
|
||||
|
||||
adapterPreference = Collections.unmodifiableList(typeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance for each adapter type
|
||||
*/
|
||||
public static LocaleProviderAdapter forType(Type type) {
|
||||
switch (type) {
|
||||
case JRE:
|
||||
return jreLocaleProviderAdapter;
|
||||
case CLDR:
|
||||
return cldrLocaleProviderAdapter;
|
||||
case SPI:
|
||||
return spiLocaleProviderAdapter;
|
||||
case HOST:
|
||||
return hostLocaleProviderAdapter;
|
||||
case FALLBACK:
|
||||
return fallbackLocaleProviderAdapter;
|
||||
default:
|
||||
throw new InternalError("unknown locale data adapter type");
|
||||
}
|
||||
}
|
||||
|
||||
public static LocaleProviderAdapter forJRE() {
|
||||
return jreLocaleProviderAdapter;
|
||||
}
|
||||
|
||||
public static LocaleProviderAdapter getResourceBundleBased() {
|
||||
for (Type type : getAdapterPreference()) {
|
||||
if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) {
|
||||
return forType(type);
|
||||
}
|
||||
}
|
||||
// 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, fallbackLocaleProviderAdapter);
|
||||
return fallbackLocaleProviderAdapter;
|
||||
}
|
||||
|
||||
private static LocaleProviderAdapter findAdapter(Class<? extends LocaleServiceProvider> providerClass,
|
||||
Locale locale) {
|
||||
for (Type type : getAdapterPreference()) {
|
||||
LocaleProviderAdapter adapter = forType(type);
|
||||
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 static boolean isSupportedLocale(Locale locale, LocaleProviderAdapter.Type type, Set<String> langtags) {
|
||||
assert type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK;
|
||||
if (Locale.ROOT.equals(locale)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == Type.FALLBACK) {
|
||||
// no other locales except ROOT are supported for FALLBACK
|
||||
return false;
|
||||
}
|
||||
|
||||
locale = locale.stripExtensions();
|
||||
if (langtags.contains(locale.toLanguageTag())) {
|
||||
return true;
|
||||
}
|
||||
if (type == Type.JRE) {
|
||||
String oldname = locale.toString().replace('_', '-');
|
||||
return langtags.contains(oldname) ||
|
||||
"ja-JP-JP".equals(oldname) ||
|
||||
"th-TH-TH".equals(oldname) ||
|
||||
"no-NO-NY".equals(oldname);
|
||||
}
|
||||
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();
|
||||
|
||||
public abstract LocaleResources getLocaleResources(Locale locale);
|
||||
|
||||
public abstract Locale[] getAvailableLocales();
|
||||
}
|
||||
510
jdkSrc/jdk8/sun/util/locale/provider/LocaleResources.java
Normal file
510
jdkSrc/jdk8/sun/util/locale/provider/LocaleResources.java
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (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 ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
|
||||
private 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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (prefix != null) {
|
||||
dateTimePattern = getDateTimePattern(prefix, "DateTimePatterns", 0, calType);
|
||||
}
|
||||
if (dateTimePattern == null) {
|
||||
dateTimePattern = getDateTimePattern(null, "DateTimePatterns", 0, calType);
|
||||
}
|
||||
switch (dateTimePattern) {
|
||||
case "{1} {0}":
|
||||
pattern = datePattern + " " + timePattern;
|
||||
break;
|
||||
case "{0} {1}":
|
||||
pattern = timePattern + " " + datePattern;
|
||||
break;
|
||||
default:
|
||||
pattern = MessageFormat.format(dateTimePattern, 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;
|
||||
}
|
||||
return ((String[])value)[styleIndex];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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 ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* A Map containing locale service providers that implement the
|
||||
* specified provider SPI, keyed by a LocaleProviderAdapter.Type
|
||||
*/
|
||||
private ConcurrentMap<LocaleProviderAdapter.Type, LocaleServiceProvider> providers =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* A Map that retains Locale->provider mapping
|
||||
*/
|
||||
private ConcurrentMap<Locale, List<LocaleProviderAdapter.Type>> 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 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;
|
||||
|
||||
for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
|
||||
LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
|
||||
if (lda != null) {
|
||||
LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
|
||||
if (provider != null) {
|
||||
providers.putIfAbsent(type, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (LocaleServiceProvider lsp : providers.values()) {
|
||||
Locale[] locales = lsp.getAvailableLocales();
|
||||
for (Locale locale: locales) {
|
||||
availableLocales.add(getLookupLocale(locale));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return availableLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether any provider for this locale sensitive
|
||||
* service is available or not, excluding JRE's one.
|
||||
*
|
||||
* @return true if any provider (other than JRE) is available
|
||||
*/
|
||||
boolean hasProviders() {
|
||||
return providers.size() != 1 ||
|
||||
(providers.get(LocaleProviderAdapter.Type.JRE) == null &&
|
||||
providers.get(LocaleProviderAdapter.Type.FALLBACK) == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
// Check whether JRE is the sole locale data provider or not,
|
||||
// and directly call it if it is.
|
||||
if (!hasProviders()) {
|
||||
return getter.getObject((P)providers.get(LocaleProviderAdapter.defaultLocaleProviderAdapter),
|
||||
locale, key, params);
|
||||
}
|
||||
|
||||
List<Locale> lookupLocales = getLookupLocales(locale);
|
||||
|
||||
Set<Locale> available = getAvailableLocaleSet();
|
||||
for (Locale current : lookupLocales) {
|
||||
if (available.contains(current)) {
|
||||
S providersObj;
|
||||
|
||||
for (LocaleProviderAdapter.Type type: findProviders(current)) {
|
||||
LocaleServiceProvider lsp = providers.get(type);
|
||||
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<LocaleProviderAdapter.Type> findProviders(Locale locale) {
|
||||
List<LocaleProviderAdapter.Type> providersList = providersCache.get(locale);
|
||||
if (providersList == null) {
|
||||
for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
|
||||
LocaleServiceProvider lsp = providers.get(type);
|
||||
if (lsp != null) {
|
||||
if (lsp.isSupportedLocale(locale)) {
|
||||
if (providersList == null) {
|
||||
providersList = new ArrayList<>(2);
|
||||
}
|
||||
providersList.add(type);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (providersList == null) {
|
||||
providersList = NULL_LIST;
|
||||
}
|
||||
List<LocaleProviderAdapter.Type> 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 List<LocaleProviderAdapter.Type> 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);
|
||||
}
|
||||
}
|
||||
@@ -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.isSupportedLocale(locale, type, 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 sun.util.resources.LocaleData;
|
||||
|
||||
/**
|
||||
* Accessor for LocaleData
|
||||
*
|
||||
* @author Naoto Sato
|
||||
*/
|
||||
public interface ResourceBundleBasedAdapter {
|
||||
public LocaleData getLocaleData();
|
||||
}
|
||||
1195
jdkSrc/jdk8/sun/util/locale/provider/RuleBasedBreakIterator.java
Normal file
1195
jdkSrc/jdk8/sun/util/locale/provider/RuleBasedBreakIterator.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* 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.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("unchecked")
|
||||
public P run() {
|
||||
P delegate = null;
|
||||
|
||||
for (LocaleServiceProvider provider : ServiceLoader.loadInstalled(c)) {
|
||||
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 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 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 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 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 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 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 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 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 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 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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.spi.TimeZoneNameProvider;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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.isSupportedLocale(locale, type, 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);
|
||||
return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
256
jdkSrc/jdk8/sun/util/locale/provider/TimeZoneNameUtility.java
Normal file
256
jdkSrc/jdk8/sun/util/locale/provider/TimeZoneNameUtility.java
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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 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) {
|
||||
return ((TimeZoneNameProviderImpl)provider).getZoneStrings(locale);
|
||||
}
|
||||
|
||||
// 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() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user