001: /* Locators.java
002:
003: {{IS_NOTE
004:
005: Purpose:
006: Description:
007: History:
008: 90/12/07 10:34:55, Create, Tom M. Yeh.
009: }}IS_NOTE
010:
011: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
012:
013: {{IS_RIGHT
014: This program is distributed under GPL Version 2.0 in the hope that
015: it will be useful, but WITHOUT ANY WARRANTY.
016: }}IS_RIGHT
017: */
018: package org.zkoss.util.resource;
019:
020: import java.io.InputStream;
021: import java.io.IOException;
022: import java.net.URL;
023: import java.util.Locale;
024:
025: import org.zkoss.util.Locales;
026: import org.zkoss.util.logging.Log;
027: import org.zkoss.lang.D;
028: import org.zkoss.lang.Classes;
029: import org.zkoss.lang.Exceptions;
030:
031: /**
032: * Utilities to load and locate resources.
033: *
034: * @author tomyeh
035: * @see Locator
036: */
037: public class Locators {
038: private static final Log log = Log.lookup(Locators.class);
039:
040: /** The default locator. */
041: private static final Locator _locator = new ClassLocator();
042:
043: /**
044: * Returns the default resource locator which is an instance of
045: * {@link ClassLocator}.
046: */
047: public static final Locator getDefault() {
048: return _locator;
049: }
050:
051: /**
052: * Locates the filename based on the locale.
053: *
054: * <p>Example, assume file="/a/b.ext" and locale="zh_TW", then
055: * the following files are tried in sequence:<br>
056: * /a/b_zh_TW.ext<br>
057: * /a/b_zh.ext<br>
058: * /a/b.ext
059: *
060: * <p>Unlike ClassLoader.getResource, it returns the found file,
061: * not the URL. In the previous example, one of /a/b_zh_TW.ext,
062: * /a/b_zh.ext and /a/b.ext will be returned.
063: *
064: * <p>To get the real URL, you still require locator.getResource:<br>
065: * <code>locator.getResource(Locators.locate(locator, "/a/b.ext", locale));</code>
066: *
067: * <p>Note: '_' is considered as a special character in the parsing,
068: * so there might be problem if a filename contains '_' used other
069: * than locale.
070: *
071: * @param locale the locale; null means the current locale
072: * @return the URL containing proper locale characters; null if not found.
073: * Note: it could compare it with the file argument with ==, because
074: * this method will return the same string if it is the result.
075: */
076: public static final URLLocation locate(String file, Locale locale,
077: Locator locator) {
078: return (URLLocation) myLocate(file, locale, locator, false);
079: }
080:
081: /**
082: * Locates the input stream based on the locale, and returns the info
083: * of StreamLocation.
084: *
085: * @see #locate
086: */
087: public static final StreamLocation locateAsStream(String file,
088: Locale locale, Locator locator) {
089: return (StreamLocation) myLocate(file, locale, locator, true);
090: }
091:
092: /** the location information. */
093: public static class URLLocation {
094: public final URL url;
095: public final String file;
096: public final Locale locale;
097:
098: public URLLocation(URL url, String file, Locale locale) {
099: this .url = url;
100: this .file = file;
101: this .locale = locale;
102: }
103:
104: public String toString() {
105: return "[url: " + url + " file=" + file + " l=" + locale
106: + ']';
107: }
108: }
109:
110: /** the location information. */
111: public static class StreamLocation {
112: public final InputStream stream;
113: public final Locale locale;
114:
115: public StreamLocation(InputStream stream, Locale locale) {
116: this .stream = stream;
117: this .locale = locale;
118: }
119: }
120:
121: /** Locates the file. */
122: private static final Object myLocate(String file, Locale locale,
123: Locator locator, boolean asStream) {
124: if (locale == null)
125: locale = Locales.getCurrent();
126:
127: final int jslash = file.lastIndexOf('/'); //>= -1
128: final int jdot = jslash >= 0 ? file.indexOf('.', jslash + 1)
129: : file.indexOf('.');
130: final String ext = jdot >= 0 ? file.substring(jdot) : "";
131: final int jul = Locales.indexOfUnderline(file,
132: jslash >= 0 ? jslash + 1 : 0);
133: final String base = file.substring(0, jul >= 0
134: && (jdot < 0 || jul < jdot) ? jul : jdot >= 0 ? jdot
135: : file.length());
136:
137: if (D.ON && log.debugable())
138: log.debug("svl=" + file + " base=" + base + " ext=" + ext);
139:
140: //search the existence based on locale
141: final int baseLen = base.length();
142: final StringBuffer sb = new StringBuffer(baseLen + 16)
143: .append(base);
144: final String[] args = new String[1];
145: final String[] secs = new String[] { locale.getLanguage(),
146: locale.getCountry(), locale.getVariant() };
147:
148: for (int j = secs.length; --j >= -1;) {
149: if (j >= 0 && secs[j].length() == 0)
150: continue;
151:
152: sb.setLength(baseLen);
153: for (int k = 0; k <= j; ++k)
154: sb.append('_').append(secs[k]);
155: sb.append(ext);
156:
157: args[0] = sb.toString();
158: final Object found = asStream ? (Object) ((Locator) locator)
159: .getResourceAsStream(args[0])
160: : (Object) ((Locator) locator).getResource(args[0]);
161: if (found != null) {
162: //decide the locale
163: final Locale l;
164: if (j >= 0) {
165: sb.setLength(0);
166: for (int k = 0; k <= j; ++k) {
167: if (k > 0)
168: sb.append('_');
169: sb.append(secs[k]);
170: }
171: l = Locales.getLocale(sb.toString(), '_');
172: } else {
173: l = Locale.ENGLISH;
174: }
175:
176: //return the info
177: if (asStream) {
178: return new StreamLocation((InputStream) found, l);
179: } else {
180: return new URLLocation((URL) found, args[0]
181: .equals(file) ? file : (String) args[0], l);
182: }
183: }
184: }
185: return null;
186: }
187: }
|