8165804: Revisit the way of loading BreakIterator rules/dictionaries

Reviewed-by: naoto, peytoia, erikj
This commit is contained in:
Masayoshi Okutsu 2016-10-25 15:43:19 +09:00
parent bf19611451
commit 6ce08d0985
13 changed files with 359 additions and 258 deletions

View File

@ -55,7 +55,6 @@ $(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_BASE, \
$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_LD, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := $(JDK_TOPDIR)/src/jdk.localedata/share/classes, \
INCLUDES := $(TEXT_PKG_LD), \
INCLUDE_FILES := \
$(TEXT_PKG_LD)/BreakIteratorRules_th.java \
$(TEXT_PKG_LD)/BreakIteratorInfo_th.java, \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -37,15 +37,10 @@
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*/
package sun.util.locale.provider;
package sun.text;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.lang.reflect.Module;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.MissingResourceException;
import sun.text.CompactByteArray;
import sun.text.SupplementaryCharacterData;
@ -137,131 +132,90 @@ class BreakDictionary {
// deserialization
//=========================================================================
BreakDictionary(Module module, String dictionaryName)
throws IOException, MissingResourceException {
readDictionaryFile(module, dictionaryName);
}
private void readDictionaryFile(final Module module, final String dictionaryName)
throws IOException, MissingResourceException {
BufferedInputStream in;
BreakDictionary(String dictionaryName, byte[] dictionaryData) {
try {
PrivilegedExceptionAction<BufferedInputStream> pa = () -> {
String pathName = "jdk.localedata".equals(module.getName()) ?
"sun/text/resources/ext/" :
"sun/text/resources/";
InputStream is = module.getResourceAsStream(pathName + dictionaryName);
if (is == null) {
// Try to load the file with "java.base" module instance. Assumption
// here is that the fall back data files to be read should reside in
// java.base.
is = BreakDictionary.class.getModule().getResourceAsStream("sun/text/resources/" + dictionaryName);
}
return new BufferedInputStream(is);
};
in = AccessController.doPrivileged(pa);
}
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",
setupDictionary(dictionaryName, dictionaryData);
} catch (BufferUnderflowException bue) {
MissingResourceException e;
e = new MissingResourceException("Corrupted dictionary data",
dictionaryName, "");
e.initCause(bue);
throw e;
}
}
private void setupDictionary(String dictionaryName, byte[] dictionaryData) {
ByteBuffer bb = ByteBuffer.wrap(dictionaryData);
// check version
int version = RuleBasedBreakIterator.getInt(buf, 0);
int version = bb.getInt();
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",
// Check data size
int len = bb.getInt();
if (bb.position() + len != bb.limit()) {
throw new MissingResourceException("Dictionary size is wrong: " + bb.limit(),
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];
len = bb.getInt();
short[] temp = new short[len];
for (int i = 0; i < len; i++) {
temp[i] = bb.getShort();
}
len = bb.getInt();
byte[] temp2 = new byte[len];
bb.get(temp2);
columnMap = new CompactByteArray(temp, temp2);
// read in numCols and numColGroups
numCols = RuleBasedBreakIterator.getInt(buf, offset);
offset += 4;
numColGroups = RuleBasedBreakIterator.getInt(buf, offset);
offset += 4;
numCols = bb.getInt();
numColGroups = bb.getInt();
// 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);
len = bb.getInt();
rowIndex = new short[len];
for (int i = 0; i < len; i++) {
rowIndex[i] = bb.getShort();
}
// 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);
len = bb.getInt();
rowIndexFlagsIndex = new short[len];
for (int i = 0; i < len; i++) {
rowIndexFlagsIndex[i] = bb.getShort();
}
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);
len = bb.getInt();
rowIndexFlags = new int[len];
for (int i = 0; i < len; i++) {
rowIndexFlags[i] = bb.getInt();
}
// 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];
}
len = bb.getInt();
rowIndexShifts = new byte[len];
bb.get(rowIndexShifts);
// 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);
len = bb.getInt();
table = new short[len];
for (int i = 0; i < len; i++) {
table[i] = bb.getShort();
}
// 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);
len = bb.getInt();
int[] temp3 = new int[len];
for (int i = 0; i < len; i++) {
temp3[i] = bb.getInt();
}
assert bb.position() == bb.limit();
supplementaryCharColumnMap = new SupplementaryCharacterData(temp3);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,10 +38,8 @@
* Taligent is a registered trademark of Taligent, Inc.
*/
package sun.util.locale.provider;
package sun.text;
import java.io.IOException;
import java.lang.reflect.Module;
import java.text.CharacterIterator;
import java.util.ArrayList;
import java.util.List;
@ -72,7 +70,7 @@ import java.util.Stack;
* slow) BuildDictionaryFile utility for creating dictionary files, but aren't
* currently making it public. Contact us for help.
*/
class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
public class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
/**
* a list of known words that is used to divide up contiguous ranges of letters,
@ -109,18 +107,22 @@ class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
/**
* Constructs a DictionaryBasedBreakIterator.
* @param module The module where the dictionary file resides
* @param dictionaryFilename The filename of the dictionary file to use
*
* @param ruleFile the name of the rule data file
* @param ruleData the rule data loaded from the rule data file
* @param dictionaryFile the name of the dictionary file
* @param dictionartData the dictionary data loaded from the dictionary file
* @throws MissingResourceException if rule data or dictionary initialization failed
*/
DictionaryBasedBreakIterator(Module module, String dataFile, String dictionaryFile)
throws IOException {
super(module, dataFile);
public DictionaryBasedBreakIterator(String ruleFile, byte[] ruleData,
String dictionaryFile, byte[] dictionaryData) {
super(ruleFile, ruleData);
byte[] tmp = super.getAdditionalData();
if (tmp != null) {
prepareCategoryFlags(tmp);
super.setAdditionalData(null);
}
dictionary = new BreakDictionary(module, dictionaryFile);
dictionary = new BreakDictionary(dictionaryFile, dictionaryData);
}
private void prepareCategoryFlags(byte[] data) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,15 +38,10 @@
* Taligent is a registered trademark of Taligent, Inc.
*/
package sun.util.locale.provider;
package sun.text;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.lang.reflect.Module;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.text.BreakIterator;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
@ -218,7 +213,7 @@ import sun.text.SupplementaryCharacterData;
*
* @author Richard Gillam
*/
class RuleBasedBreakIterator extends BreakIterator {
public class RuleBasedBreakIterator extends BreakIterator {
/**
* A token used as a character-category value to identify ignore characters
@ -249,11 +244,6 @@ class RuleBasedBreakIterator extends BreakIterator {
*/
static final byte supportedVersion = 1;
/**
* Header size in byte count
*/
private static final int HEADER_LENGTH = 36;
/**
* An array length of indices for BMP characters
*/
@ -315,16 +305,26 @@ class RuleBasedBreakIterator extends BreakIterator {
//=======================================================================
/**
* Constructs a RuleBasedBreakIterator according to the module and the datafile
* provided.
* Constructs a RuleBasedBreakIterator using the given rule data.
*
* @throws MissingResourceException if the rule data is invalid or corrupted
*/
RuleBasedBreakIterator(Module module, String datafile)
throws IOException, MissingResourceException {
readTables(module, datafile);
public RuleBasedBreakIterator(String ruleFile, byte[] ruleData) {
ByteBuffer bb = ByteBuffer.wrap(ruleData);
try {
validateRuleData(ruleFile, bb);
setupTables(ruleFile, bb);
} catch (BufferUnderflowException bue) {
MissingResourceException e;
e = new MissingResourceException("Corrupted rule data file", ruleFile, "");
e.initCause(bue);
throw e;
}
}
/**
* Read datafile. The datafile's format is as follows:
* Initializes the fields with the given rule data.
* The data format is as follows:
* <pre>
* BreakIteratorData {
* u1 magic[7];
@ -370,133 +370,101 @@ class RuleBasedBreakIterator extends BreakIterator {
* u1 additionalData[additionalDataLength];
* }
* </pre>
*
* @throws BufferUnderflowException if the end-of-data is reached before
* setting up all the tables
*/
protected final void readTables(Module module, String datafile)
throws IOException, MissingResourceException {
byte[] buffer = readFile(module, datafile);
private void setupTables(String ruleFile, ByteBuffer bb) {
/* Read header_info. */
int stateTableLength = getInt(buffer, 0);
int backwardsStateTableLength = getInt(buffer, 4);
int endStatesLength = getInt(buffer, 8);
int lookaheadStatesLength = getInt(buffer, 12);
int BMPdataLength = getInt(buffer, 16);
int nonBMPdataLength = getInt(buffer, 20);
int additionalDataLength = getInt(buffer, 24);
checksum = getLong(buffer, 28);
int stateTableLength = bb.getInt();
int backwardsStateTableLength = bb.getInt();
int endStatesLength = bb.getInt();
int lookaheadStatesLength = bb.getInt();
int BMPdataLength = bb.getInt();
int nonBMPdataLength = bb.getInt();
int additionalDataLength = bb.getInt();
checksum = bb.getLong();
/* Read stateTable[numCategories * numRows] */
stateTable = new short[stateTableLength];
int offset = HEADER_LENGTH;
for (int i = 0; i < stateTableLength; i++, offset+=2) {
stateTable[i] = getShort(buffer, offset);
for (int i = 0; i < stateTableLength; i++) {
stateTable[i] = bb.getShort();
}
/* Read backwardsStateTable[numCategories * numRows] */
backwardsStateTable = new short[backwardsStateTableLength];
for (int i = 0; i < backwardsStateTableLength; i++, offset+=2) {
backwardsStateTable[i] = getShort(buffer, offset);
for (int i = 0; i < backwardsStateTableLength; i++) {
backwardsStateTable[i] = bb.getShort();
}
/* Read endStates[numRows] */
endStates = new boolean[endStatesLength];
for (int i = 0; i < endStatesLength; i++, offset++) {
endStates[i] = buffer[offset] == 1;
for (int i = 0; i < endStatesLength; i++) {
endStates[i] = bb.get() == 1;
}
/* Read lookaheadStates[numRows] */
lookaheadStates = new boolean[lookaheadStatesLength];
for (int i = 0; i < lookaheadStatesLength; i++, offset++) {
lookaheadStates[i] = buffer[offset] == 1;
for (int i = 0; i < lookaheadStatesLength; i++) {
lookaheadStates[i] = bb.get() == 1;
}
/* Read a category table and indices for BMP characters. */
short[] temp1 = new short[BMP_INDICES_LENGTH]; // BMPindices
for (int i = 0; i < BMP_INDICES_LENGTH; i++, offset+=2) {
temp1[i] = getShort(buffer, offset);
for (int i = 0; i < BMP_INDICES_LENGTH; i++) {
temp1[i] = bb.getShort();
}
byte[] temp2 = new byte[BMPdataLength]; // BMPdata
System.arraycopy(buffer, offset, temp2, 0, BMPdataLength);
offset += BMPdataLength;
bb.get(temp2);
charCategoryTable = new CompactByteArray(temp1, temp2);
/* Read a category table for non-BMP characters. */
int[] temp3 = new int[nonBMPdataLength];
for (int i = 0; i < nonBMPdataLength; i++, offset+=4) {
temp3[i] = getInt(buffer, offset);
for (int i = 0; i < nonBMPdataLength; i++) {
temp3[i] = bb.getInt();
}
supplementaryCharCategoryTable = new SupplementaryCharacterData(temp3);
/* Read additional data */
if (additionalDataLength > 0) {
additionalData = new byte[additionalDataLength];
System.arraycopy(buffer, offset, additionalData, 0, additionalDataLength);
bb.get(additionalData);
}
assert bb.position() == bb.limit();
/* Set numCategories */
numCategories = stateTable.length / endStates.length;
}
protected byte[] readFile(final Module module, final String datafile)
throws IOException, MissingResourceException {
BufferedInputStream is;
try {
PrivilegedExceptionAction<BufferedInputStream> pa = () -> {
String pathName = "jdk.localedata".equals(module.getName()) ?
"sun/text/resources/ext/" :
"sun/text/resources/";
InputStream in = module.getResourceAsStream(pathName + datafile);
if (in == null) {
// Try to load the file with "java.base" module instance. Assumption
// here is that the fall back data files to be read should reside in
// java.base.
in = RuleBasedBreakIterator.class.getModule().getResourceAsStream("sun/text/resources/" + datafile);
}
return new BufferedInputStream(in);
};
is = AccessController.doPrivileged(pa);
} catch (PrivilegedActionException e) {
throw new InternalError(e.toString(), e);
}
int offset = 0;
/* First, read magic, version, and header_info. */
int len = LABEL_LENGTH + 5;
byte[] buf = new byte[len];
if (is.read(buf) != len) {
throw new MissingResourceException("Wrong header length",
datafile, "");
}
/* Validate the magic number. */
for (int i = 0; i < LABEL_LENGTH; i++, offset++) {
if (buf[offset] != LABEL[offset]) {
/**
* Validates the magic number, version, and the length of the given data.
*
* @throws BufferUnderflowException if the end-of-data is reached while
* validating data
* @throws MissingResourceException if valification failed
*/
void validateRuleData(String ruleFile, ByteBuffer bb) {
/* Verify the magic number. */
for (int i = 0; i < LABEL_LENGTH; i++) {
if (bb.get() != LABEL[i]) {
throw new MissingResourceException("Wrong magic number",
datafile, "");
ruleFile, "");
}
}
/* Validate the version number. */
if (buf[offset] != supportedVersion) {
throw new MissingResourceException("Unsupported version(" + buf[offset] + ")",
datafile, "");
/* Verify the version number. */
byte version = bb.get();
if (version != supportedVersion) {
throw new MissingResourceException("Unsupported version(" + version + ")",
ruleFile, "");
}
/* Read data: totalDataSize + 8(for checksum) */
len = getInt(buf, ++offset);
buf = new byte[len];
if (is.read(buf) != len) {
// Check the length of the rest of data
int len = bb.getInt();
if (bb.position() + len != bb.limit()) {
throw new MissingResourceException("Wrong data length",
datafile, "");
ruleFile, "");
}
is.close();
return buf;
}
byte[] getAdditionalData() {
@ -1061,28 +1029,6 @@ class RuleBasedBreakIterator extends BreakIterator {
return backwardsStateTable[state * numCategories + category];
}
static long getLong(byte[] buf, int offset) {
long num = buf[offset]&0xFF;
for (int i = 1; i < 8; i++) {
num = num<<8 | (buf[offset+i]&0xFF);
}
return num;
}
static int getInt(byte[] buf, int offset) {
int num = buf[offset]&0xFF;
for (int i = 1; i < 4; i++) {
num = num<<8 | (buf[offset+i]&0xFF);
}
return num;
}
static short getShort(byte[] buf, int offset) {
short num = (short)(buf[offset]&0xFF);
num = (short)(num<<8 | (buf[offset+1]&0xFF));
return num;
}
/*
* This class exists to work around a bug in incorrect implementations
* of CharacterIterator, which incorrectly handle setIndex(endIndex).

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,8 @@ import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Set;
import sun.text.DictionaryBasedBreakIterator;
import sun.text.RuleBasedBreakIterator;
/**
* Concrete implementation of the {@link java.text.spi.BreakIteratorProvider
@ -154,28 +156,30 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider
private BreakIterator getBreakInstance(Locale locale,
int type,
String dataName,
String ruleName,
String dictionaryName) {
Objects.requireNonNull(locale);
LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses");
String dataFile = (String) lr.getBreakIteratorInfo(dataName);
String ruleFile = (String) lr.getBreakIteratorInfo(ruleName);
byte[] ruleData = lr.getBreakIteratorResources(ruleName);
try {
switch (classNames[type]) {
case "RuleBasedBreakIterator":
return new RuleBasedBreakIterator(
lr.getBreakIteratorDataModule(), dataFile);
return new RuleBasedBreakIterator(ruleFile, ruleData);
case "DictionaryBasedBreakIterator":
String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName);
return new DictionaryBasedBreakIterator(
lr.getBreakIteratorDataModule(), dataFile, dictionaryFile);
byte[] dictionaryData = lr.getBreakIteratorResources(dictionaryName);
return new DictionaryBasedBreakIterator(ruleFile, ruleData,
dictionaryFile, dictionaryData);
default:
throw new IllegalArgumentException("Invalid break iterator class \"" +
classNames[type] + "\"");
}
} catch (IOException | MissingResourceException | IllegalArgumentException e) {
} catch (MissingResourceException | IllegalArgumentException e) {
throw new InternalError(e.toString(), e);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -42,7 +42,6 @@ package sun.util.locale.provider;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Module;
import java.text.MessageFormat;
import java.util.Calendar;
import java.util.LinkedHashSet;
@ -118,8 +117,9 @@ public class LocaleResources {
return biInfo;
}
Module getBreakIteratorDataModule() {
return localeData.getBreakIteratorInfo(locale).getClass().getModule();
@SuppressWarnings("unchecked")
byte[] getBreakIteratorResources(String key) {
return (byte[]) localeData.getBreakIteratorResources(locale).getObject(key);
}
int getCalendarData(String key) {

View File

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

View File

@ -122,6 +122,14 @@ public class LocaleData {
return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale);
}
/**
* Gets a break iterator resources resource bundle, using
* privileges to allow accessing a sun.* package.
*/
public ResourceBundle getBreakIteratorResources(Locale locale) {
return getBundle(type.getTextResourcesPackage() + ".BreakIteratorResources", locale);
}
/**
* Gets a collation data resource bundle, using privileges
* to allow accessing a sun.* package.

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -89,7 +89,7 @@ public class BreakIteratorProviderTest extends ProviderTest {
String[] jresResult = new String[4];
if (jreSupportsLocale) {
for (int i = 0; i < 4; i++) {
jresResult[i] = "sun.util.locale.provider."+classNames[i];
jresResult[i] = "sun.text." + classNames[i];
}
}

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -23,6 +23,6 @@
#
#
# @test
# @bug 4052440 8062588
# @bug 4052440 8062588 8165804
# @summary BreakIteratorProvider tests
# @run shell ExecTest.sh foo BreakIteratorProviderTest

View File

@ -40,7 +40,7 @@ import tests.Result;
/*
* @test
* @bug 8152143 8152704 8155649
* @bug 8152143 8152704 8155649 8165804
* @summary IncludeLocalesPlugin tests
* @author Naoto Sato
* @library ../../lib
@ -236,6 +236,7 @@ public class IncludeLocalesPluginTest {
"/jdk.localedata/sun/text/resources/ext/thai_dict",
"/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorResources_th.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_ja.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_th.class",
@ -261,6 +262,7 @@ public class IncludeLocalesPluginTest {
"/jdk.localedata/sun/text/resources/ext/thai_dict",
"/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class",
"/jdk.localedata/sun/text/resources/ext/BreakIteratorResources_th.class",
"/jdk.localedata/sun/text/resources/ext/FormatData_th.class"),
List.of(
"/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class",