001: /*
002: *
003: * @(#)LocaleData.java 1.36 06/10/10
004: *
005: * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights
006: * Reserved. Use is subject to license terms.
007: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
008: *
009: * This program is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU General Public License version
011: * 2 only, as published by the Free Software Foundation.
012: *
013: * This program is distributed in the hope that it will be useful, but
014: * WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License version 2 for more details (a copy is
017: * included at /legal/license.txt).
018: *
019: * You should have received a copy of the GNU General Public License
020: * version 2 along with this work; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022: * 02110-1301 USA
023: *
024: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
025: * Clara, CA 95054 or visit www.sun.com if you need additional
026: * information or have any questions.
027: */
028:
029: /*
030: * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
031: * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
032: *
033: * The original version of this source code and documentation
034: * is copyrighted and owned by Taligent, Inc., a wholly-owned
035: * subsidiary of IBM. These materials are provided under terms
036: * of a License Agreement between Taligent and Sun. This technology
037: * is protected by multiple US and International patents.
038: *
039: * This notice and attribution to Taligent may not be removed.
040: * Taligent is a registered trademark of Taligent, Inc.
041: *
042: */
043:
044: package sun.text.resources;
045:
046: import java.io.File;
047: import java.io.FileInputStream;
048: import java.io.FileNotFoundException;
049: import java.io.IOException;
050: import java.net.URL;
051: import java.net.URLClassLoader;
052: import java.security.AccessController;
053: import java.security.PrivilegedAction;
054: import java.util.Locale;
055: import java.util.ResourceBundle;
056: import java.util.Hashtable;
057: import java.util.Vector;
058: import java.util.zip.ZipEntry;
059: import java.io.File;
060: import java.util.zip.ZipInputStream;
061: import sun.misc.Launcher;
062:
063: /**
064: * Provides information about and access to resource bundles in the
065: * sun.text.resources package.
066: * This class now exists only to allow a way to get the list of available resources. Even
067: * this will be changing in the future.
068: *
069: * @author Asmus Freytag
070: * @author Mark Davis
071: * @version 1.34 01/23/03
072: */
073:
074: public class LocaleData {
075: /**
076: * Returns a list of the installed locales.
077: * @param key A resource tag. Currently, this parameter is ignored. The obvious
078: * intent, however, is for getAvailableLocales() to return a list of only those
079: * locales that contain a resource with the specified resource tag.
080: *
081: * <p>Before we implement this function this way, however, some thought should be
082: * given to whether this is really the right thing to do. Because of the lookup
083: * algorithm, a NumberFormat, for example, is "installed" for all locales. But if
084: * we're trying to put up a list of NumberFormats to choose from, we may want to see
085: * only a list of those locales that uniquely define a NumberFormat rather than
086: * inheriting one from another locale. Thus, if fr and fr_CA uniquely define
087: * NumberFormat data, but fr_BE doesn't, the user wouldn't see "French (Belgium)" in
088: * the list and would go for "French (default)" instead. Of course, this means
089: * "English (United States)" would not be in the list, since it is the default locale.
090: * This might be okay, but might be confusing to some users.
091: *
092: * <p>In addition, the other functions that call getAvailableLocales() don't currently
093: * all pass the right thing for "key," meaning that all of these functions should be
094: * looked at before anything is done to this function.
095: *
096: * <p>We recommend that someone take some careful consideration of these issues before
097: * modifying this function to pay attention to the "key" parameter. --rtg 1/26/98
098: */
099: public static Locale[] getAvailableLocales(String key) {
100: // creating the locale list is expensive, so be careful to do it
101: // only once
102: if (localeList == null) {
103: synchronized (LocaleData.class) {
104: if (localeList == null) {
105: localeList = createLocaleList();
106: }
107: }
108: }
109:
110: Locale[] temp = new Locale[localeList.length];
111: System.arraycopy(localeList, 0, temp, 0, localeList.length);
112: return temp;
113: }
114:
115: /**
116: * Gets a sun.text.resources.LocaleElements resource bundle, using privileges
117: * to allow accessing a sun.* package.
118: */
119: public static ResourceBundle getLocaleElements(Locale locale) {
120: return getBundle("sun.text.resources.LocaleElements", locale);
121: }
122:
123: /**
124: * Gets a sun.text.resources.DateFormatZoneData resource bundle, using privileges
125: * to allow accessing a sun.* package.
126: */
127: public static ResourceBundle getDateFormatZoneData(Locale locale) {
128: return getBundle("sun.text.resources.DateFormatZoneData",
129: locale);
130: }
131:
132: private static ResourceBundle getBundle(final String baseName,
133: final Locale locale) {
134: return (ResourceBundle) AccessController
135: .doPrivileged(new PrivilegedAction() {
136: public Object run() {
137: return ResourceBundle.getBundle(baseName,
138: locale);
139: }
140: });
141: }
142:
143: // ========== privates ==========
144:
145: private static Vector classPathSegments = new Vector();
146: private static Locale[] localeList;
147: private static final String PACKAGE = "sun.text.resources";
148: private static final String PREFIX = "LocaleElements_";
149: private static final char ZIPSEPARATOR = '/';
150:
151: private static Locale[] createLocaleList() {
152: Locale[] locales;
153: String classPath = (String) java.security.AccessController
154: .doPrivileged(new sun.security.action.GetPropertyAction(
155: "sun.boot.class.path"));
156: String s = (String) java.security.AccessController
157: .doPrivileged(new sun.security.action.GetPropertyAction(
158: "java.class.path"));
159:
160: // Search combined system and application class path
161: if (s != null && s.length() != 0) {
162: classPath += File.pathSeparator + s;
163: }
164: while (classPath != null && classPath.length() != 0) {
165: int i = classPath
166: .lastIndexOf(java.io.File.pathSeparatorChar);
167: String dir = classPath.substring(i + 1);
168: if (i == -1) {
169: classPath = null;
170: } else {
171: classPath = classPath.substring(0, i);
172: }
173: classPathSegments.insertElementAt(dir, 0);
174: }
175:
176: // add extensions from the extension class loader
177: ClassLoader appLoader = Launcher.getLauncher().getClassLoader();
178: URLClassLoader extLoader = (URLClassLoader) appLoader
179: .getParent();
180: if (extLoader != null) {
181: URL[] urls = extLoader.getURLs();
182: for (int i = 0; i < urls.length; i++) {
183: classPathSegments.insertElementAt(urls[i].getPath(), 0);
184: }
185: }
186:
187: String[] classList = (String[]) java.security.AccessController
188: .doPrivileged(new java.security.PrivilegedAction() {
189: public Object run() {
190: return getClassList(PACKAGE, PREFIX);
191: }
192: });
193:
194: /*
195: * When all library classes are romized, no cdc.jar or foundation.jar
196: * exists, so we would fail to create the correct locale data by just
197: * searching through sun.boot.class.path and java.class.path.
198: * To solve the problem, we use a generated java class,
199: * sun.misc.DefaultLocaleList. This class is generated at build time.
200: * The generated class contains a list of default locale information
201: * gathered by parsing build-time class (romized classes) list.
202: */
203: int plen = PREFIX.length();
204: localeList = new Locale[classList.length
205: + sun.misc.DefaultLocaleList.list.length];
206: /* 1. search sun.boot.class.path and java.class.path. */
207: for (int i = 0; i < classList.length; i++) {
208: localeList[i] = getLocale(classList[i].substring(plen));
209: }
210:
211: /* 2. add locale information generated from romized classes if
212: * there is any
213: */
214: for (int j = 0; j < sun.misc.DefaultLocaleList.list.length; j++) {
215: localeList[classList.length + j] = getLocale(sun.misc.DefaultLocaleList.list[j]);
216: }
217: return (localeList);
218: }
219:
220: private static Locale getLocale(String s) {
221: String lang = "";
222: String region = "";
223: String var = "";
224: int p1 = s.indexOf('_');
225: int p2 = 0;
226:
227: if (p1 == -1) {
228: lang = s;
229: } else {
230: lang = s.substring(0, p1);
231: p2 = s.indexOf('_', p1 + 1);
232: if (p2 == -1) {
233: region = s.substring(p1 + 1);
234: } else {
235: region = s.substring(p1 + 1, p2);
236: if (p2 < s.length()) {
237: var = s.substring(p2 + 1);
238: }
239: }
240: }
241:
242: return new Locale(lang, region, var);
243: }
244:
245: /**
246: * Walk through CLASSPATH and find class list from a package.
247: * The class names start with prefix string
248: * @param package name, class name prefix
249: * @return class list in an array of String
250: */
251: private static String[] getClassList(String pkgName, String prefix) {
252: Vector listBuffer = new Vector();
253: String packagePath = pkgName.replace('.', File.separatorChar)
254: + File.separatorChar;
255: String zipPackagePath = pkgName.replace('.', ZIPSEPARATOR)
256: + ZIPSEPARATOR;
257: for (int i = 0; i < classPathSegments.size(); i++) {
258: String onePath = (String) classPathSegments.elementAt(i);
259: File f = new File(onePath);
260: if (!f.exists())
261: continue;
262: if (f.isFile())
263: scanFile(f, zipPackagePath, listBuffer, prefix);
264: else if (f.isDirectory()) {
265: String fullPath;
266: if (onePath.endsWith(File.separator))
267: fullPath = onePath + packagePath;
268: else
269: fullPath = onePath + File.separatorChar
270: + packagePath;
271: File dir = new File(fullPath);
272: if (dir.exists() && dir.isDirectory())
273: scanDir(dir, listBuffer, prefix);
274: }
275: }
276: String[] classNames = new String[listBuffer.size()];
277: listBuffer.copyInto(classNames);
278: return classNames;
279: }
280:
281: private static void addClass(String className, Vector listBuffer,
282: String prefix) {
283: if (className != null && className.startsWith(prefix)
284: && !listBuffer.contains(className))
285: listBuffer.addElement(className);
286: }
287:
288: private static String midString(String str, String pre, String suf) {
289: String midStr;
290: if (str.startsWith(pre) && str.endsWith(suf))
291: midStr = str.substring(pre.length(), str.length()
292: - suf.length());
293: else
294: midStr = null;
295: return midStr;
296: }
297:
298: private static void scanDir(File dir, Vector listBuffer,
299: String prefix) {
300: String[] fileList = dir.list();
301: for (int i = 0; i < fileList.length; i++) {
302: addClass(midString(fileList[i], "", ".class"), listBuffer,
303: prefix);
304: }
305: }
306:
307: private static void scanFile(File f, String packagePath,
308: Vector listBuffer, String prefix) {
309: try {
310: ZipInputStream zipFile = new ZipInputStream(
311: new FileInputStream(f));
312: boolean gotThere = false;
313: ZipEntry entry;
314: while ((entry = zipFile.getNextEntry()) != null) {
315: String eName = entry.getName();
316: if (eName.startsWith(packagePath)) {
317: gotThere = true;
318: if (eName.endsWith(".class")) {
319: addClass(
320: midString(eName, packagePath, ".class"),
321: listBuffer, prefix);
322: }
323: } else {
324: if (gotThere) // Found the package, now we are leaving
325: break;
326: }
327: }
328: } catch (FileNotFoundException e) {
329: System.out.println("file not found:" + e);
330: } catch (IOException e) {
331: System.out.println("file IO Exception:" + e);
332: } catch (Exception e) {
333: System.out.println("Exception:" + e);
334: }
335: }
336: }
|