View Javadoc

1   /*
2    * This software was designed and created by Jason Carroll.
3    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
4    * The author can be reached at jcarroll@cowsultants.com
5    * ITracker website: http://www.cowsultants.com
6    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
7    *
8    * This program is free software; you can redistribute it and/or modify
9    * it only under the terms of the GNU General Public License as published by
10   * the Free Software Foundation; either version 2 of the License, or
11   * (at your option) any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   */
18  
19  package org.itracker.core.resources;
20  
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.MissingResourceException;
28  import java.util.ResourceBundle;
29  import java.util.Set;
30  
31  import org.apache.log4j.Logger;
32  import org.itracker.model.Language;
33  import org.itracker.persistence.dao.NoSuchEntityException;
34  import org.itracker.services.exceptions.ITrackerDirtyResourceException;
35  import org.itracker.web.util.LoginUtilities;
36  import org.itracker.web.util.ServletContextUtils;
37  
38  /**
39   * 
40   * Please comment this class here. What is it for?
41   * 
42   * @author ready
43   * 
44   */
45  public class ITrackerResources {
46  
47  	private static final Logger logger = Logger
48  			.getLogger(ITrackerResources.class);
49  
50  	public static final String RESOURCE_BUNDLE_NAME = "org.itracker.core.resources.ITracker";
51  
52  	public static final String DEFINED_LOCALES_KEY = "itracker.locales";
53  
54  	public static final String DEFAULT_LOCALE = "en_US";
55  
56  	public static final String BASE_LOCALE = "BASE";
57  
58  	public static final String NO_LOCALE = "ZZ_ZZ";
59  
60  	public static final String KEY_BASE_CUSTOMFIELD_TYPE = "itracker.web.generic.";
61  
62  	public static final String KEY_BASE_WORKFLOW_EVENT = "itracker.workflow.field.event.";
63  
64  	public static final String KEY_BASE_PROJECT_STATUS = "itracker.project.status.";
65  
66  	public static final String KEY_BASE_PERMISSION = "itracker.user.permission.";
67  
68  	public static final String KEY_BASE_PRIORITY = "itracker.script.priority.";
69  
70  	public static final String KEY_BASE_PRIORITY_LABEL = ".label";
71  
72  	public static final String KEY_BASE_PRIORITY_SIZE = "size";
73  
74  	public static final String KEY_BASE_RESOLUTION = "itracker.resolution.";
75  
76  	public static final String KEY_BASE_ISSUE_RELATION = "itracker.issuerelation.";
77  
78  	public static final String KEY_BASE_SEVERITY = "itracker.severity.";
79  
80  	public static final String KEY_BASE_STATUS = "itracker.status.";
81  
82  	public static final String KEY_BASE_USER_STATUS = "itracker.user.status.";
83  
84  	public static final String KEY_BASE_CUSTOMFIELD = "itracker.customfield.";
85  
86  	public static final String KEY_BASE_CUSTOMFIELD_OPTION = ".option.";
87  
88  	public static final String KEY_BASE_CUSTOMFIELD_LABEL = ".label";
89  
90  	public static final String KEY_BASE_LOCALE_NAME = "itracker.locale.name";
91  
92  	private static String defaultLocale = DEFAULT_LOCALE;
93  
94  	private static HashMap<String, Locale> locales = new HashMap<String, Locale>();
95  
96  	private static HashMap<Locale, ResourceBundle> languages = new HashMap<Locale, ResourceBundle>();
97  
98  	private static boolean initialized = false;
99  
100 	private static Object bundleLock = new Object();
101 
102 	// private static ConfigurationService configurationService;
103 
104 	public static Locale getLocale() {
105 		return getLocale(getDefaultLocale());
106 	}
107 
108 	public static Locale getLocale(String localeString) {
109 
110 //		if (logger.isDebugEnabled()) {
111 //			logger.debug("getLocale: " + localeString);
112 //		}
113 		if (localeString == null || localeString.trim().equals("")) {
114 			return getLocale(getDefaultLocale());
115 		}
116 
117 		Locale locale = locales.get(localeString);
118 		if (locale == null && localeString != null
119 				&& !localeString.trim().equals("")) {
120 			try {
121 				if (logger.isDebugEnabled()) {
122 					logger.debug("Creating new locale for '" + localeString
123 							+ "'");
124 				}
125 				if (localeString.length() == 5) {
126 					locale = new Locale(localeString.substring(0, 2),
127 							localeString.substring(3));
128 				} else if (localeString.length() == 2) {
129 					locale = new Locale(localeString, "");
130 				} else if (localeString.equals(BASE_LOCALE)) {
131 					locale = new Locale("", "");
132 				} else {
133 
134 					logger
135 								.error("Invalid locale '"
136 										+ localeString
137 										+ "' specified.  It must be either LN or LN_CN.");
138 					throw new Exception("Invalid locale string");
139 				}
140 			} catch (Exception ex) {
141 				if (!localeString.equals(getDefaultLocale())) {
142 					logger.error("Failed creating new locale for '"
143 							+ localeString
144 							+ "' attempting for default locale '"
145 							+ getDefaultLocale() + "'", ex);
146 					return getLocale(getDefaultLocale());
147 				} else {
148 					logger.error("Failed creating new default locale for '"
149 							+ getDefaultLocale()
150 							+ "' attempting for DEFAULT_LOCALE '"
151 							+ DEFAULT_LOCALE + "'", ex);
152 					return getLocale(DEFAULT_LOCALE);
153 				}
154 			}
155 			locales.put(localeString, locale);
156 		}
157 		return locale;
158 	}
159 
160 	public static String getDefaultLocale() {
161 		return (defaultLocale == null ? DEFAULT_LOCALE : defaultLocale);
162 	}
163 
164 	public static void setDefaultLocale(String value) {
165 		defaultLocale = value;
166 	}
167 
168 	public static String getLocaleDN(String locale, Locale displayLocale) {
169 		String name;
170 		if (null == displayLocale) {
171 			displayLocale = getLocale();
172 		}
173 		try {
174 			name = getBundle(displayLocale).getString(
175 					KEY_BASE_LOCALE_NAME + "." + locale);
176 		} catch (RuntimeException e) {
177 			name = getLocaleNativeName(getLocale(locale));
178 		}
179 
180 		return name;
181 	}
182 
183 	public static String getLocaleDN(Locale locale, Locale displayLocale) {
184 
185 		if (null == displayLocale) {
186 			return getLocaleNativeName(displayLocale);
187 		}
188 		return getLocaleDN(locale.toString(), displayLocale);
189 
190 	}
191 	public static String getLocaleFullDN(Locale locale, Locale displayLocale) {
192 
193 		if (null == locale) {
194 			locale = new Locale("");
195 		}
196 		String fullName = getLocaleNativeName(locale);
197 		if (null == displayLocale || locale.getLanguage().equals(displayLocale.getLanguage())) {
198 			return fullName;
199 		}
200 		if (fullName.equals(locale.toString())) {
201 			fullName = getLocaleDN(locale, displayLocale);
202 		} else {
203 			String localizedName = getLocaleDN(locale, displayLocale);
204 			if (null != fullName && null != localizedName && !localizedName.trim().equals(fullName.trim())) {
205 				return fullName.trim() + " (" + localizedName.trim() + ")";
206 			} else if (null != localizedName) {
207 				return localizedName.trim();
208 			} else if (null != fullName) {
209 				return fullName.trim();
210 			}
211 			
212 		}
213 		
214 		return "Unknown: " + locale.toString();
215 
216 	}
217 	public static String getLocaleNativeName(Locale locale) {
218 		try {
219 			return getString(KEY_BASE_LOCALE_NAME, locale);
220 //			return getBundle(locale).getString(KEY_BASE_LOCALE_NAME);
221 		} catch (MissingResourceException e) {
222 			return locale.toString();
223 //			return locale.getDisplayName(locale);
224 		}
225 	}
226 
227 	public static final Map<String, String> getLocaleNamesMap(Locale locale, Set<String> languageCodes,Map<String, List<String>> languagesMap ) {
228 		Map<String, String> ret = new LinkedHashMap<String, String>();
229 		for (String languageCode : languageCodes) {
230 			List<String> languagelist = languagesMap.get(languageCode);
231 			
232 			String name = getLocaleFullDN(ITrackerResources.getLocale(languageCode), locale);
233 
234 			ret.put(languageCode, name);
235 			for (String languageitem : languagelist) {
236 				name = getLocaleFullDN(ITrackerResources.getLocale(languageitem), locale);
237 				ret.put(languageitem, name);
238 			}
239 
240 		}
241 		if (ret.size() == 0) {
242 			ret.put(getDefaultLocale(), getLocaleNativeName(getLocale(getDefaultLocale())));
243 		}
244 		return ret;
245 		
246 	}
247 	public static ResourceBundle getBundle() {
248 		return getBundle(getDefaultLocale());
249 	}
250 
251 	public static ResourceBundle getBundle(String locale) {
252 		if (locale == null || locale.equals("")) {
253 			locale = getDefaultLocale();
254 		}
255 
256 		return getBundle(getLocale(locale));
257 	}
258 
259 	public static ResourceBundle getBundle(Locale locale) {
260 		if (locale == null) {
261 			locale = getLocale(getDefaultLocale());
262 		}
263 		ResourceBundle bundle = (ResourceBundle) languages.get(locale);
264 		if (bundle == null) {
265 			if (logger.isDebugEnabled()) {
266 				logger.debug("getBundle: Loading new resource bundle for locale " + locale
267 					+ " from the database.");
268 			}
269 			List<Language> languageItems = ServletContextUtils
270 					.getItrackerServices().getConfigurationService()
271 					.getLanguage(locale);
272 //			if (locale.getLanguage().equals("")) {
273 //				locale = getLocale()
274 //			}
275 			bundle = ITrackerResourceBundle.loadBundle(locale, languageItems);
276 			if (logger.isDebugEnabled()) {
277 				logger.debug("getBundle: got loaded for locale " + locale
278 					+ " with items " + languageItems + " from the database.");
279 			}
280 			if (bundle != null) {
281 				putBundle(locale, bundle);
282 			} else if (!locale.toString().equals(getDefaultLocale())) {
283 				bundle = getBundle(getLocale());
284 			}
285 		}
286 
287 		return bundle;
288 	}
289 
290 	public static ResourceBundle getEditBundle(Locale locale) {
291 		if (locale == null) {
292 			locale = getLocale(getDefaultLocale());
293 		}
294 		ResourceBundle bundle = (ResourceBundle) languages.get(locale);
295 		logger.debug("Loading new resource bundle for locale " + locale
296 				+ " from the database.");
297 		List<Language> languageItems = ServletContextUtils
298 				.getItrackerServices().getConfigurationService().getLanguage(
299 						locale);
300 		bundle = ITrackerResourceBundle.loadBundle(locale, languageItems);
301 		if (bundle != null) {
302 			putBundle(locale, bundle);
303 		} else if (!locale.toString().equals(getDefaultLocale())) {
304 			bundle = getBundle(getLocale());
305 		}
306 
307 		return bundle;
308 	}
309 
310 	public static void putBundle(Locale locale, ResourceBundle bundle) {
311 		if (locale != null && bundle != null) {
312 			synchronized (bundleLock) {
313 				languages.put(locale, bundle);
314 //				if (bundle instanceof ITrackerResourceBundle) {
315 //					setData((ITrackerResourceBundle)bundle);
316 //				}
317 				String localeString = locale.toString();
318 				if (localeString.length() == 5) {
319 					localeString = localeString.substring(0, 2) + "_"
320 							+ localeString.substring(3).toUpperCase();
321 				}
322 				locales.put(localeString, locale);
323 			}
324 		}
325 	}
326 
327 	static void setData(ITrackerResourceBundle bundle) {
328 
329 		List<Language> languageItems = ServletContextUtils
330 				.getItrackerServices().getConfigurationService()
331 				.getLanguage(bundle.getLocale());
332 		bundle.setContents(languageItems);
333 	}
334 	/**
335 	 * Clears a single cached resource bundle. The next time the bundle is
336 	 * accessed, it will be reloaded and placed into the cache.
337 	 */
338 	public static void clearBundle(Locale locale) {
339 		if (locale != null) {
340 			synchronized (bundleLock) {
341 				ResourceBundle bundle = languages.get(locale);
342 //				if (bundle instanceof ITrackerResourceBundle) {
343 //					((ITrackerResourceBundle)bundle).
344 //				}
345 				languages.remove(locale);
346 			}
347 		}
348 	}
349 
350 	/**
351 	 * Clears all cached resource bundles. The next time a bundle is accessed,
352 	 * it will be reloaded and placed into the cache.
353 	 */
354 	public static void clearBundles() {
355 		synchronized (bundleLock) {
356 
357 			languages.clear();
358 			
359 		}
360 	}
361 
362 	/**
363 	 * Clears a single key from all cached resource bundles. The key is then
364 	 * marked that it is dirty and should be reloaded on hte next access.
365 	 */
366 	public static void clearKeyFromBundles(String key, boolean markDirty) {
367 		if (key != null) {
368 			synchronized (bundleLock) {
369 				for (Iterator<ResourceBundle> iter = languages.values()
370 						.iterator(); iter.hasNext();) {
371 					((ITrackerResourceBundle) iter.next()).removeValue(key,
372 							markDirty);
373 				}
374 			}
375 		}
376 	}
377 
378 	public static String getString(String key) {
379 		return getString(key, getLocale(defaultLocale));
380 	}
381 
382 	public static String getString(String key, String locale) {
383 		if (key == null) {
384 			return "";
385 		}
386 
387 		if (locale == null || locale.equals("")) {
388 			locale = getDefaultLocale();
389 		}
390 
391 		return getString(key, getLocale(locale));
392 	}
393 
394 	public static String getString(String key, Locale locale) {
395 		if (key == null) {
396 			return "";
397 		}
398 
399 		if (locale == null) {
400 			locale = getLocale(getDefaultLocale());
401 		}
402 		String val;
403 		try {
404 			try {
405 //				 if (logger.isDebugEnabled()) {
406 //				 logger.debug("getString: " + key + " for locale " + locale);
407 //				 }
408 				val = getBundle(locale).getString(key);
409 				if (null != val) {
410 
411 //					 if (logger.isDebugEnabled()) {
412 //					 logger.debug("getString: found " + val + " for key" + key
413 //					 + ", locale " + locale);
414 //					 }
415 					return val;
416 				} else {
417 					val = ITrackerResources.getString(key);
418 
419 //					 if (logger.isDebugEnabled()) {
420 //					 logger.debug("getString: found in base: " + val +
421 //					 " for key" + key);
422 //					 }
423 				}
424 			} catch (ITrackerDirtyResourceException idre) {
425 
426 //				 logger.debug("Loading new key to replace dirty key " + key +
427 //				 " for resource bundle for locale "
428 //				 + locale);
429 				Language languageItem = ServletContextUtils
430 						.getItrackerServices().getConfigurationService()
431 						.getLanguageItemByKey(key, locale);
432 				ResourceBundle bundle = getBundle(locale);
433 				((ITrackerResourceBundle) bundle)
434 						.updateValue(languageItem);
435 				val = bundle.getString(key);
436 			}
437 			return val;
438 		} catch (NullPointerException ex) {
439 			logger.error(
440 					"Unable to get any resources.  The requested locale was "
441 							+ locale, ex);
442 			return "MISSING BUNDLE: " + locale;
443 		} catch (MissingResourceException ex) {
444 			logger.warn(
445 					"MissingResourceException caught while retrieving translation key '"
446 							+ key + "' for locale " + locale, ex);
447 			return "MISSING KEY: " + key;
448 		} catch (NoSuchEntityException ex) {
449 			logger.info("getString: not found " + key + " locale: " + locale,
450 					ex);
451 			try {
452 				return getEditBundle(locale).getString(key);
453 			} catch (Exception ex2) {
454 				logger.warn(
455 						"getString: caught while retrieving translation key '"
456 								+ key + "' for locale " + locale, ex2);
457 				return "MISSING KEY: " + key;
458 			}
459 		}
460 	}
461 
462 	public static String getString(String key, Object[] options) {
463 		return getString(key, getLocale(getDefaultLocale()), options);
464 	}
465 
466 	public static String getString(String key, String locale, Object[] options) {
467 		return getString(key, getLocale(locale), options);
468 	}
469 
470 	public static String getString(String key, Locale locale, Object[] options) {
471 		String message = getString(key, locale);
472 		return MessageFormat.format(message, options, locale);
473 	}
474 
475 	public static String getString(String key, String locale, String option) {
476 		String message = getString(key, locale);
477 		return MessageFormat.format(message, new Object[] { option },
478 				getLocale(locale));
479 	}
480 
481 	public static String getString(String key, Locale locale, String option) {
482 		String message = getString(key, locale);
483 		return MessageFormat.format(message, new Object[] { option }, locale);
484 	}
485 
486 	public static String getCheckForKey(String key)
487 			throws MissingResourceException {
488 		return getCheckForKey(key, getLocale());
489 	}
490 
491 	public static String getCheckForKey(String key, Locale locale)
492 			throws MissingResourceException {
493 		try {
494 			return getBundle(locale).getString(key);
495 		} catch (ITrackerDirtyResourceException idre) {
496 			return getString(key, locale);
497 		} catch (NullPointerException ex) {
498 			logger.error("Unable to get ResourceBundle for locale " + locale,
499 					ex);
500 			throw new MissingResourceException("MISSING LOCALE: " + locale,
501 					"ITrackerResources", key);
502 		}
503 	}
504 
505 	public static boolean isLongString(String key) {
506 		String value = getString(key);
507 		if (value.length() > 80 || value.indexOf('\n') > 0) {
508 			return true;
509 		}
510 		return false;
511 	}
512 
513 	public static String escapeUnicodeString(String str, boolean escapeAll) {
514 		if (str == null) {
515 			return "";
516 		}
517 
518 		StringBuffer sb = new StringBuffer();
519 		for (int i = 0; i < str.length(); i++) {
520 			char ch = str.charAt(i);
521 			if (!escapeAll && ((ch >= 0x0020) && (ch <= 0x007e))) {
522 				sb.append(ch);
523 			} else {
524 				sb.append('\\').append('u');
525 				sb.append(encodeHex((ch >> 12) & 0xF));
526 				sb.append(encodeHex((ch >> 8) & 0xF));
527 				sb.append(encodeHex((ch >> 4) & 0xF));
528 				sb.append(encodeHex(ch & 0xF));
529 			}
530 		}
531 		return sb.toString();
532 	}
533 
534 	public static String unescapeUnicodeString(String str) {
535 		StringBuffer sb = new StringBuffer();
536 
537 		for (int i = 0; i < str.length();) {
538 			char ch = str.charAt(i++);
539 			if (ch == '\\') {
540 				if (str.charAt(i++) == 'u') {
541 					int value = 0;
542 					for (int j = 0; j < 4; j++) {
543 						value = (value << 4) + decodeHex(str.charAt(i++));
544 					}
545 					sb.append((char) value);
546 				} else {
547 					sb.append("\\" + str.charAt(i));
548 				}
549 			} else {
550 				sb.append(ch);
551 			}
552 		}
553 		return sb.toString();
554 	}
555 
556 	public static final String HEXCHARS = "0123456789ABCDEF";
557 
558 	public static char encodeHex(int value) {
559 		return HEXCHARS.charAt(value & 0xf);
560 	}
561 
562 	public static int decodeHex(char ch) {
563 		int value = -1;
564 
565 		if (ch >= '0' && ch <= '9') {
566 			value = ch - '0';
567 		} else if (ch >= 'a' && ch <= 'f') {
568 			value = ch - 'a' + 10;
569 		} else if (ch >= 'A' && ch <= 'F') {
570 			value = ch - 'A' + 10;
571 		}
572 
573 		return value;
574 	}
575 
576 	// public static void setConfigurationService(ConfigurationService
577 	// configurationService) {
578 	// ITrackerResources.configurationService = configurationService;
579 	// }
580 
581 	public static boolean isInitialized() {
582 		return initialized;
583 	}
584 
585 	public static void setInitialized(boolean initialized) {
586 		ITrackerResources.initialized = initialized;
587 	}
588 
589 	public static String getParentLocale(String locale) {
590 		String localeCode = locale;
591 		if (localeCode == null) {
592 			localeCode = getDefaultLocale();
593 		} else if (localeCode.equals(getDefaultLocale())) {
594 			localeCode = BASE_LOCALE;
595 		} else {
596 			Locale l = getLocale(locale);
597 
598 			if (!l.getVariant().equals("")) {
599 				localeCode = l.getLanguage() + "_" + l.getCountry();
600 			}
601 			if (!l.getCountry().equals("")) {
602 				localeCode = l.getLanguage();
603 			}
604 			if (!l.getLanguage().equals("")) {
605 				localeCode = getDefaultLocale();
606 			}
607 		}
608 		return localeCode;
609 	}
610 
611 }