Java tutorial
/* * This software was designed and created by Jason Carroll. * Copyright (c) 2002, 2003, 2004 Jason Carroll. * The author can be reached at jcarroll@cowsultants.com * ITracker website: http://www.cowsultants.com * ITracker forums: http://www.cowsultants.com/phpBB/index.php * * This program is free software; you can redistribute it and/or modify * it only under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 for more details. */ package org.itracker.core.resources; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.itracker.ITrackerDirtyResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; /** * Please comment this class here. What is it for? * * @author ready */ public class ITrackerResources { private static final Logger logger = LoggerFactory.getLogger(ITrackerResources.class); public static final String RESOURCE_BUNDLE_NAME = "org.itracker.core.resources.ITracker"; public static final String DEFAULT_LOCALE = "en_US"; public static final String BASE_LOCALE = "BASE"; public static final String KEY_BASE_CUSTOMFIELD_TYPE = "itracker.web.generic."; public static final String KEY_BASE_WORKFLOW_EVENT = "itracker.workflow.field.event."; public static final String KEY_BASE_PROJECT_STATUS = "itracker.project.status."; public static final String KEY_BASE_PERMISSION = "itracker.user.permission."; public static final String KEY_BASE_PRIORITY = "itracker.script.priority."; public static final String KEY_BASE_PRIORITY_LABEL = ".label"; public static final String KEY_BASE_PRIORITY_SIZE = "size"; public static final String KEY_BASE_RESOLUTION = "itracker.resolution."; public static final String KEY_BASE_ISSUE_RELATION = "itracker.issuerelation."; public static final String KEY_BASE_SEVERITY = "itracker.severity."; public static final String KEY_BASE_STATUS = "itracker.status."; public static final String KEY_BASE_USER_STATUS = "itracker.user.status."; public static final String KEY_BASE_CUSTOMFIELD = "itracker.customfield."; public static final String KEY_BASE_CUSTOMFIELD_OPTION = ".option."; public static final String KEY_BASE_CUSTOMFIELD_LABEL = ".label"; public static final String KEY_BASE_LOCALE_NAME = "itracker.locale.name"; private static String defaultLocale = DEFAULT_LOCALE; private static HashMap<String, Locale> locales = new HashMap<String, Locale>(); private static HashMap<Locale, ResourceBundle> languages = new HashMap<Locale, ResourceBundle>(); private static ITrackerResourcesProvider configurationService; private static Collection<String> availableLocales; private static boolean initialized = false; private static final Object bundleLock = new Object(); public static Locale getLocale() { return getLocale(getDefaultLocale()); } public static Locale getLocale(String localeString) { if (localeString == null || localeString.trim().equals("")) { return getLocale(getDefaultLocale()); } Locale locale = locales.get(localeString); if (locale == null && !StringUtils.isEmpty(localeString)) { try { if (logger.isDebugEnabled()) { logger.debug("Creating new locale for '" + localeString + "'"); } if (localeString.length() == 5) { locale = new Locale(localeString.substring(0, 2), localeString.substring(3)); } else if (localeString.length() == 2) { locale = new Locale(localeString, ""); } else if (localeString.equals(BASE_LOCALE)) { locale = new Locale("", ""); } else { logger.error( "Invalid locale '" + localeString + "' specified. It must be either LN or LN_CN."); throw new Exception("Invalid locale string"); } } catch (Exception ex) { if (!localeString.equals(getDefaultLocale())) { logger.error("Failed creating new locale for '" + localeString + "' attempting for default locale '" + getDefaultLocale() + "'", ex); return getLocale(getDefaultLocale()); } else { logger.error("Failed creating new default locale for '" + getDefaultLocale() + "' attempting for DEFAULT_LOCALE '" + DEFAULT_LOCALE + "'", ex); return getLocale(DEFAULT_LOCALE); } } locales.put(localeString, locale); } return locale; } public static String getDefaultLocale() { return (defaultLocale == null ? DEFAULT_LOCALE : defaultLocale); } private static void setDefaultLocale(String value) { defaultLocale = value; } public static String getLocaleDN(String locale, Locale displayLocale) { String name; if (null == displayLocale) { displayLocale = getLocale(); } try { name = getBundle(displayLocale).getString(KEY_BASE_LOCALE_NAME + "." + locale); } catch (RuntimeException e) { name = getLocaleNativeName(getLocale(locale)); } return name; } public static String getLocaleDN(Locale locale, Locale displayLocale) { if (null == displayLocale) { return getLocaleNativeName(displayLocale); } return getLocaleDN(locale.toString(), displayLocale); } public static String getLocaleFullDN(Locale locale, Locale displayLocale) { if (null == locale) { locale = new Locale(""); } String fullName = StringUtils.trimToNull(getLocaleNativeName(locale)); if (null == displayLocale || locale.getLanguage().equals(displayLocale.getLanguage())) { return fullName; } if (StringUtils.equals(fullName, String.valueOf(locale))) { fullName = getLocaleDN(locale, displayLocale); return fullName; } else { String localizedName = StringUtils.trimToNull(getLocaleDN(locale, displayLocale)); if (null != fullName && !StringUtils.equals(fullName, localizedName)) { return fullName.trim() + " (" + localizedName.trim() + ")"; } else if (null != localizedName) { return localizedName.trim(); } else if (null != fullName) { return fullName.trim(); } } return locale.getDisplayName() + (!locale.equals(displayLocale) ? " (" + locale.getDisplayLanguage(locale) + ")" : ""); } public static String getLocaleNativeName(Locale locale) { try { return getString(KEY_BASE_LOCALE_NAME, locale); } catch (MissingResourceException e) { return locale.getDisplayName(locale); } } public static Map<String, String> getLocaleNamesMap(Locale locale, Set<String> languageCodes, Map<String, List<String>> languagesMap) { Map<String, String> ret = new LinkedHashMap<String, String>(); for (String languageCode : languageCodes) { List<String> languagelist = languagesMap.get(languageCode); String name = getLocaleFullDN(ITrackerResources.getLocale(languageCode), locale); ret.put(languageCode, name); for (String languageitem : languagelist) { name = getLocaleFullDN(ITrackerResources.getLocale(languageitem), locale); ret.put(languageitem, name); } } if (ret.size() == 0) { ret.put(getDefaultLocale(), getLocaleNativeName(getLocale(getDefaultLocale()))); } return ret; } public static ResourceBundle getBundle() { return getBundle(getDefaultLocale()); } public static ResourceBundle getBundle(String locale) { if (locale == null || locale.equals("")) { locale = getDefaultLocale(); } return getBundle(getLocale(locale)); } public static ResourceBundle getBundle(Locale locale) { if (locale == null) { locale = getLocale(); } ResourceBundle bundle = languages.get(locale); if (bundle == null) { if (logger.isDebugEnabled()) { logger.debug("getBundle: Loading new resource bundle for locale " + locale + " from the database."); } if (!isInitialized()) { return ITrackerResourceBundle.loadBundle(locale); } else { Properties languageItems = configurationService.getLanguageProperties(locale); logger.info("lazy loading locale bundle resources: {}", locale); bundle = ITrackerResourceBundle.loadBundle(locale, languageItems); logger.info("getBundle: got loaded for locale {} with {} items from the database.", locale, null == languageItems ? "no" : CollectionUtils.size(languageItems)); logger.debug("getBundle: got loaded for locale {} with items {} from the database.", locale, languageItems); putBundle(locale, bundle); } } return bundle; } public static ResourceBundle getEditBundle(Locale locale) { if (locale == null) { locale = getLocale(getDefaultLocale()); } ResourceBundle bundle; logger.debug("Loading new resource bundle for locale " + locale + " from the database."); Properties languageItems = configurationService.getLanguageProperties(locale); bundle = ITrackerResourceBundle.loadBundle(locale, languageItems); putBundle(locale, bundle); return bundle; } public static void putBundle(Locale locale, ResourceBundle bundle) { if (locale != null && bundle != null) { synchronized (bundleLock) { languages.put(locale, bundle); String localeString = locale.toString(); if (localeString.length() == 5) { localeString = localeString.substring(0, 2) + "_" + localeString.substring(3).toUpperCase(); } locales.put(localeString, locale); } } } /** * Clears a single cached resource bundle. The next time the bundle is * accessed, it will be reloaded and placed into the cache. */ public static void clearBundle(Locale locale) { if (locale != null) { synchronized (bundleLock) { languages.remove(locale); } } } /** * Clears all cached resource bundles. The next time a bundle is accessed, * it will be reloaded and placed into the cache. */ public static void clearBundles() { synchronized (bundleLock) { languages.clear(); } } /** * Clears a single key from all cached resource bundles. The key is then * marked that it is dirty and should be reloaded on hte next access. */ public static void clearKeyFromBundles(String key, boolean markDirty) { if (key != null) { synchronized (bundleLock) { for (ResourceBundle resourceBundle : languages.values()) { ((ITrackerResourceBundle) resourceBundle).removeValue(key, markDirty); } } } } public static String getString(String key) { return getString(key, getLocale(defaultLocale)); } public static String getString(String key, String locale) { if (key == null) { return ""; } if (locale == null || locale.equals("")) { locale = getDefaultLocale(); } return getString(key, getLocale(locale)); } private static String handleMissingResourceException(final MissingResourceException ex, final String key, final Locale locale) { logger.warn("no value while retrieving translation key '{}' for locale {}", key, locale); Locale l = locale; if (null == l) { l = getLocale(getDefaultLocale()); } if (StringUtils.isNotEmpty(l.getCountry())) { l = new Locale(l.getLanguage()); } else if (StringUtils.isNotEmpty(l.getLanguage())) { l = new Locale(""); } if (l != locale) { logger.debug("resolving {}from parent bundle ()", key, l); return getString(key, l); } throw ex; } private static String handleDirtyResourceException(final ITrackerDirtyResourceException e, final String key, final Locale locale) { logger.debug("handleDirtyResourceException: key '{}' for locale {}", new Object[] { key, locale, e }); ITrackerResourceBundle bundle = (ITrackerResourceBundle) getBundle(locale); try { final String languageItem = configurationService.getLanguageEntry(key, locale); bundle.updateValue(key, languageItem); return languageItem; } catch (MissingResourceException e2) { bundle.removeValue(key, false); try { return bundle.getString(key); } catch (MissingResourceException e3) { return handleMissingResourceException(e2, key, locale); } } } public static String getString(final String key, final Locale locale) { if (key == null) { return ""; } String val; try { final ResourceBundle bundle = getBundle(locale); try { val = bundle.getString(key); return val; } catch (ITrackerDirtyResourceException e) { val = handleDirtyResourceException(e, key, locale); } catch (MissingResourceException e) { val = handleMissingResourceException(e, key, locale); } return val; } catch (NullPointerException ex) { logger.error("Unable to get any resources. The requested locale was " + locale, ex); return "MISSING BUNDLE: " + locale; } catch (MissingResourceException ex) { logger.warn("MissingResourceException caught while retrieving translation key '{}' for locale {}", key, locale); logger.debug("MissingResourceException was", ex); return "MISSING KEY: " + key; } catch (RuntimeException ex) { logger.info("getString: not found " + key + " locale: " + locale, ex); try { return getEditBundle(locale).getString(key); } catch (Exception ex2) { logger.warn("Exception caught while retrieving translation key '{}' for locale {}: {}", new Object[] { key, locale, ex2.getMessage() }); logger.debug("Exception was", ex2); return "MISSING KEY: " + key; } } } public static String getString(String key, Object[] options) { return getString(key, getLocale(getDefaultLocale()), options); } public static String getString(String key, String locale, Object[] options) { return getString(key, getLocale(locale), options); } public static String getString(String key, Locale locale, Object[] options) { String message = getString(key, locale); return MessageFormat.format(message, options, locale); } public static String getString(String key, String locale, String option) { String message = getString(key, locale); return MessageFormat.format(message, new Object[] { option }, getLocale(locale)); } public static String getString(String key, Locale locale, String option) { String message = getString(key, locale); return MessageFormat.format(message, new Object[] { option }, locale); } public static String getCheckForKey(String key) throws MissingResourceException { return getCheckForKey(key, getLocale()); } public static String getCheckForKey(String key, Locale locale) throws MissingResourceException { try { return getBundle(locale).getString(key); } catch (ITrackerDirtyResourceException idre) { return getString(key, locale); } catch (NullPointerException ex) { logger.debug("Unable to get ResourceBundle for locale " + locale, ex); throw new MissingResourceException("MISSING LOCALE: " + locale, "ITrackerResources", key); } } public static boolean isLongString(String key) { String value = getString(key); return value.length() > 80 || value.indexOf('\n') > 0; } public static String escapeUnicodeString(String str, boolean escapeAll) { if (str == null) { return ""; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); if (!escapeAll && ((ch >= 0x0020) && (ch <= 0x007e))) { sb.append(ch); } else { sb.append('\\').append('u'); sb.append(encodeHex((ch >> 12) & 0xF)); sb.append(encodeHex((ch >> 8) & 0xF)); sb.append(encodeHex((ch >> 4) & 0xF)); sb.append(encodeHex(ch & 0xF)); } } return sb.toString(); } public static String unescapeUnicodeString(String str) { final StringBuilder sb = new StringBuilder(); for (int i = 0; i < str.length();) { char ch = str.charAt(i++); if (ch == '\\') { if (str.charAt(i++) == 'u') { int value = 0; for (int j = 0; j < 4; j++) { value = (value << 4) + decodeHex(str.charAt(i++)); } sb.append((char) value); } else { sb.append("\\").append(str.charAt(i)); } } else { sb.append(ch); } } return sb.toString(); } public static final String HEXCHARS = "0123456789ABCDEF"; public static char encodeHex(int value) { return HEXCHARS.charAt(value & 0xf); } public static int decodeHex(char ch) { int value = -1; if (ch >= '0' && ch <= '9') { value = ch - '0'; } else if (ch >= 'a' && ch <= 'f') { value = ch - 'a' + 10; } else if (ch >= 'A' && ch <= 'F') { value = ch - 'A' + 10; } return value; } public static boolean isInitialized() { return initialized; } private static void setInitialized(boolean initialized) { ITrackerResources.initialized = initialized; } public static void setConfigurationService(ITrackerResourcesProvider service) { if (isInitialized()) { throw new IllegalStateException("Service is already set up."); } configurationService = service; String[] availableLocales = StringUtils .split(configurationService.getProperty("available_locales", getDefaultLocale()), ','); ArrayList<String> locales = new ArrayList<>(availableLocales.length); for (String l : availableLocales) { locales.add(StringUtils.trim(l)); } ITrackerResources.availableLocales = locales; ITrackerResources.setDefaultLocale( configurationService.getProperty("default_locale", ITrackerResources.DEFAULT_LOCALE)); logger.info("Set system default locale to '" + ITrackerResources.getDefaultLocale() + "'"); setInitialized(true); } }