001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/trunk/sakai/admin-tools/su/src/java/org/sakaiproject/tool/su/SuTool.java $
003: * $Id: SuTool.java 5970 2006-02-15 03:07:19Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.util;
021:
022: import java.text.MessageFormat;
023: import java.util.Collection;
024: import java.util.Enumeration;
025: import java.util.Hashtable;
026: import java.util.Locale;
027: import java.util.Map;
028: import java.util.MissingResourceException;
029: import java.util.ResourceBundle;
030: import java.util.Set;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.sakaiproject.entity.api.ResourceProperties;
035: import org.sakaiproject.i18n.InternationalizedMessages;
036: import org.sakaiproject.tool.cover.SessionManager;
037: import org.sakaiproject.user.api.Preferences;
038: import org.sakaiproject.user.cover.PreferencesService;
039:
040: /**
041: * ResourceLoader provides an alternate implementation of org.util.ResourceBundle, dynamically selecting the prefered locale from either the user's session or from the user's sakai preferences
042: *
043: * @author Sugiura, Tatsuki (University of Nagoya)
044: */
045: public class ResourceLoader extends DummyMap implements
046: InternationalizedMessages {
047: protected static Log M_log = LogFactory
048: .getLog(ResourceLoader.class);
049:
050: protected String baseName = null;
051:
052: protected Hashtable bundles = new Hashtable();
053:
054: /**
055: * Default constructor (does nothing)
056: */
057: public ResourceLoader() {
058: }
059:
060: /**
061: * Constructor: set baseName
062: *
063: * @param name
064: * default ResourceBundle base filename
065: */
066: public ResourceLoader(String name) {
067: setBaseName(name);
068: }
069:
070: public Set entrySet() {
071: return getBundleAsMap().entrySet();
072: }
073:
074: /**
075: * * Return (generic object) value for specified property in current locale specific ResourceBundle * *
076: *
077: * @param key
078: * property key to look up in current ResourceBundle * *
079: * @return value for specified property key
080: */
081: public Object get(Object key) {
082: return getString(key.toString());
083: }
084:
085: /**
086: ** Return formatted message based on locale-specific pattern
087: **
088: ** @param key maps to locale-specific pattern in properties file
089: ** @param args parameters to format and insert according to above pattern
090: ** @return formatted message
091: **/
092: public String getFormattedMessage(String key, Object[] args) {
093: String pattern = (String) get(key);
094: return (new MessageFormat(pattern, getLocale())).format(args,
095: new StringBuffer(), null).toString();
096: }
097:
098: /**
099: * Access some named configuration value as an int.
100: *
101: * @param key
102: * property key to look up in current ResourceBundle
103: * @param dflt
104: * The value to return if not found.
105: * @return The property value with this name, or the default value if not found.
106: */
107: public int getInt(String key, int dflt) {
108: String value = getString(key);
109:
110: if (value.length() == 0)
111: return dflt;
112:
113: try {
114: return Integer.parseInt(value);
115: } catch (NumberFormatException e) {
116: // ignore
117: return dflt;
118: }
119: }
120:
121: /**
122: * * Return user's prefered locale * First: return locale from Sakai user preferences, if available * Second: return locale from user session, if available * Last: return system default locale * *
123: *
124: * @return user's Locale object
125: */
126: public Locale getLocale() {
127: Locale loc = null;
128:
129: // First: find locale from Sakai user preferences, if available
130: try {
131: String userId = SessionManager.getCurrentSessionUserId();
132: Preferences prefs = PreferencesService
133: .getPreferences(userId);
134: ResourceProperties locProps = prefs
135: .getProperties(APPLICATION_ID);
136:
137: String localeString = locProps.getProperty(LOCALE_KEY);
138: if (localeString != null) {
139: String[] locValues = localeString.split("_");
140: if (locValues.length > 1)
141: loc = new Locale(locValues[0], locValues[1]); // language, country
142: else if (locValues.length == 1)
143: loc = new Locale(locValues[0]); // just language
144: }
145: } catch (Exception e) {
146: } // ignore and continue
147:
148: // Second: find locale from user session, if available
149: if (loc == null) {
150: try {
151: loc = (Locale) SessionManager.getCurrentSession()
152: .getAttribute("locale");
153: } catch (NullPointerException e) {
154: } // ignore and continue
155: }
156:
157: // Last: find system default locale
158: if (loc == null) {
159: // fallback to default.
160: loc = Locale.getDefault();
161: } else if (!Locale.getDefault().getLanguage().equals("en")
162: && loc.getLanguage().equals("en")) {
163: // Tweak for English: en is default locale. It has no suffix in filename.
164: loc = new Locale("");
165: }
166:
167: return loc;
168: }
169:
170: /**
171: * * Return string value for specified property in current locale specific ResourceBundle * *
172: *
173: * @param key
174: * property key to look up in current ResourceBundle * *
175: * @return String value for specified property key
176: */
177: public String getString(String key) {
178: try {
179: return getBundle().getString(key);
180: } catch (MissingResourceException e) {
181: M_log.warn("Missing key: " + key);
182: return "[missing key: " + key + "]";
183: }
184: }
185:
186: /**
187: * Return string value for specified property in current locale specific ResourceBundle
188: *
189: * @param key
190: * property key to look up in current ResourceBundle
191: * @param dflt
192: * the default value to be returned in case the property is missing
193: * @return String value for specified property key
194: */
195: public String getString(String key, String dflt) {
196: try {
197: return getBundle().getString(key);
198: } catch (MissingResourceException e) {
199: return dflt;
200: }
201: }
202:
203: /**
204: * Access some named property values as an array of strings. The name is the base name. name + ".count" must be defined to be a positive integer - how many are defined. name + "." + i (1..count) must be defined to be the values.
205: *
206: * @param key
207: * property key to look up in current ResourceBundle
208: * @return The property value with this name, or the null if not found.
209: */
210: public String[] getStrings(String key) {
211: // get the count
212: int count = getInt(key + ".count", 0);
213: if (count > 0) {
214: String[] rv = new String[count];
215: for (int i = 1; i <= count; i++) {
216: String value = "";
217: try {
218: value = getBundle().getString(key + "." + i);
219: } catch (MissingResourceException e) {
220: // ignore the exception
221: }
222: rv[i - 1] = value;
223: }
224: return rv;
225: }
226:
227: return null;
228: }
229:
230: public Set keySet() {
231: return getBundleAsMap().keySet();
232: }
233:
234: /**
235: * * Clear bundles hashmap
236: */
237: public void purgeCache() {
238: this .bundles = new Hashtable();
239: M_log.debug("purge bundle cache");
240: }
241:
242: /**
243: * Set baseName
244: *
245: * @param name
246: * default ResourceBundle base filename
247: */
248: public void setBaseName(String name) {
249: M_log.debug("set baseName=" + name);
250: this .baseName = name;
251: }
252:
253: public Collection values() {
254: return getBundleAsMap().values();
255: }
256:
257: /**
258: * Return ResourceBundle for user's preferred locale
259: *
260: * @return user's ResourceBundle object
261: */
262: protected ResourceBundle getBundle() {
263: Locale loc = getLocale();
264: ResourceBundle bundle = (ResourceBundle) this .bundles.get(loc);
265: if (bundle == null) {
266: M_log.debug("Load bundle name=" + this .baseName
267: + ", locale=" + getLocale().toString());
268: bundle = loadBundle(loc);
269: }
270: return bundle;
271: }
272:
273: protected Map getBundleAsMap() {
274: Map bundle = new Hashtable();
275:
276: for (Enumeration e = getBundle().getKeys(); e.hasMoreElements();) {
277: Object key = e.nextElement();
278: bundle.put(key, getBundle().getObject((String) key));
279: }
280:
281: return bundle;
282: }
283:
284: /**
285: * Return ResourceBundle for specified locale
286: *
287: * @param bundle
288: * properties bundle * *
289: * @return locale specific ResourceBundle
290: */
291: protected ResourceBundle loadBundle(Locale loc) {
292: ResourceBundle newBundle = null;
293: try {
294: newBundle = ResourceBundle.getBundle(this .baseName, loc);
295: } catch (NullPointerException e) {
296: } // ignore
297:
298: setBundle(loc, newBundle);
299: return newBundle;
300: }
301:
302: /**
303: * Add loc (key) and bundle (value) to this.bundles hash
304: *
305: * @param loc
306: * Language/Region Locale *
307: * @param bundle
308: * properties bundle
309: */
310: protected void setBundle(Locale loc, ResourceBundle bundle) {
311: if (bundle == null)
312: throw new NullPointerException();
313: this .bundles.put(loc, bundle);
314: }
315: }
316:
317: abstract class DummyMap implements Map {
318: public void clear() {
319: throw new UnsupportedOperationException();
320: }
321:
322: public boolean containsKey(Object key) {
323: return true;
324: }
325:
326: public boolean containsValue(Object value) {
327: throw new UnsupportedOperationException();
328: }
329:
330: public Set entrySet() {
331: throw new UnsupportedOperationException();
332: }
333:
334: public abstract Object get(Object key);
335:
336: public boolean isEmpty() {
337: throw new UnsupportedOperationException();
338: }
339:
340: public Set keySet() {
341: throw new UnsupportedOperationException();
342: }
343:
344: public Object put(Object arg0, Object arg1) {
345: throw new UnsupportedOperationException();
346: }
347:
348: public void putAll(Map arg0) {
349: throw new UnsupportedOperationException();
350: }
351:
352: public Object remove(Object key) {
353: throw new UnsupportedOperationException();
354: }
355:
356: public int size() {
357: throw new UnsupportedOperationException();
358: }
359:
360: public Collection values() {
361: throw new UnsupportedOperationException();
362: }
363: }
|