001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.language;
016    
017    import com.liferay.portal.kernel.language.LanguageUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.CharPool;
021    import com.liferay.portal.kernel.util.LocaleUtil;
022    import com.liferay.portal.kernel.util.PropertiesUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
027    import com.liferay.portal.tools.LangBuilder;
028    
029    import java.io.InputStream;
030    
031    import java.net.URL;
032    
033    import java.util.Collections;
034    import java.util.Enumeration;
035    import java.util.HashMap;
036    import java.util.Locale;
037    import java.util.Map;
038    import java.util.Properties;
039    import java.util.concurrent.ConcurrentHashMap;
040    
041    /**
042     * @author Shuyang Zhou
043     */
044    public class LanguageResources {
045    
046            public static String fixValue(String value) {
047                    if (value.endsWith(LangBuilder.AUTOMATIC_COPY)) {
048                            value = value.substring(
049                                    0, value.length() - LangBuilder.AUTOMATIC_COPY.length());
050                    }
051    
052                    if (value.endsWith(LangBuilder.AUTOMATIC_TRANSLATION)) {
053                            value = value.substring(
054                                    0, value.length() - LangBuilder.AUTOMATIC_TRANSLATION.length());
055                    }
056    
057                    return value;
058            }
059    
060            public static void fixValues(
061                    Map<String, String> languageMap, Properties properties) {
062    
063                    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
064                            String key = (String)entry.getKey();
065                            String value = (String)entry.getValue();
066    
067                            value = fixValue(value);
068    
069                            languageMap.put(key, value);
070                    }
071            }
072    
073            public static String getMessage(Locale locale, String key) {
074                    if (locale == null) {
075                            return null;
076                    }
077    
078                    Map<String, String> languageMap = _languageMaps.get(locale);
079    
080                    if (languageMap == null) {
081                            languageMap = _loadLocale(locale);
082                    }
083    
084                    String value = languageMap.get(key);
085    
086                    if (value == null) {
087                            return getMessage(getSuperLocale(locale), key);
088                    }
089                    else {
090                            return value;
091                    }
092            }
093    
094            public static Locale getSuperLocale(Locale locale) {
095                    String variant = locale.getVariant();
096    
097                    if (variant.length() > 0) {
098                            return new Locale(locale.getLanguage(), locale.getCountry());
099                    }
100    
101                    String country = locale.getCountry();
102    
103                    if (country.length() > 0) {
104                            Locale priorityLocale = LanguageUtil.getLocale(
105                                    locale.getLanguage());
106    
107                            if ((priorityLocale != null) && !locale.equals(priorityLocale)) {
108                                    return new Locale(
109                                            priorityLocale.getLanguage(), priorityLocale.getCountry());
110                            }
111    
112                            return LocaleUtil.fromLanguageId(locale.getLanguage());
113                    }
114    
115                    String language = locale.getLanguage();
116    
117                    if (language.length() > 0) {
118                            return _blankLocale;
119                    }
120    
121                    return null;
122            }
123    
124            public static Map<String, String> putLanguageMap(
125                    Locale locale, Map<String, String> languageMap) {
126    
127                    Map<String, String> oldLanguageMap = _languageMaps.get(locale);
128    
129                    if (oldLanguageMap == null) {
130                            _loadLocale(locale);
131                            oldLanguageMap = _languageMaps.get(locale);
132                    }
133    
134                    Map<String, String> newLanguageMap = new HashMap<String, String>();
135    
136                    if (oldLanguageMap != null) {
137                            newLanguageMap.putAll(oldLanguageMap);
138                    }
139    
140                    newLanguageMap.putAll(languageMap);
141    
142                    _languageMaps.put(locale, newLanguageMap);
143    
144                    return oldLanguageMap;
145            }
146    
147            public void setConfig(String config) {
148                    _configNames = StringUtil.split(
149                            config.replace(CharPool.PERIOD, CharPool.SLASH));
150            }
151    
152            private static Map<String, String> _loadLocale(Locale locale) {
153                    Map<String, String> languageMap = null;
154    
155                    if (_configNames.length > 0) {
156                            String localeName = locale.toString();
157    
158                            languageMap = new HashMap<String, String>();
159    
160                            for (String name : _configNames) {
161                                    StringBundler sb = new StringBundler(4);
162    
163                                    sb.append(name);
164    
165                                    if (localeName.length() > 0) {
166                                            sb.append(StringPool.UNDERLINE);
167                                            sb.append(localeName);
168                                    }
169    
170                                    sb.append(".properties");
171    
172                                    Properties properties = _loadProperties(sb.toString());
173    
174                                    fixValues(languageMap, properties);
175                            }
176                    }
177                    else {
178                            languageMap = Collections.emptyMap();
179                    }
180    
181                    _languageMaps.put(locale, languageMap);
182    
183                    return languageMap;
184            }
185    
186            private static Properties _loadProperties(String name) {
187                    Properties properties = new Properties();
188    
189                    boolean enabled = PortalSecurityManagerThreadLocal.isEnabled();
190    
191                    try {
192                            PortalSecurityManagerThreadLocal.setEnabled(false);
193    
194                            ClassLoader classLoader = LanguageResources.class.getClassLoader();
195    
196                            Enumeration<URL> enu = classLoader.getResources(name);
197    
198                            if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
199                                    _log.debug("No resources found for " + name);
200                            }
201    
202                            while (enu.hasMoreElements()) {
203                                    URL url = enu.nextElement();
204    
205                                    if (_log.isInfoEnabled()) {
206                                            _log.debug("Loading " + name + " from " + url);
207                                    }
208    
209                                    InputStream inputStream = url.openStream();
210    
211                                    try {
212                                            Properties inputStreamProperties = PropertiesUtil.load(
213                                                    inputStream, StringPool.UTF8);
214    
215                                            properties.putAll(inputStreamProperties);
216    
217                                            if (_log.isInfoEnabled()) {
218                                                    _log.info(
219                                                            "Loading " + url + " with " +
220                                                                    inputStreamProperties.size() + " values");
221                                            }
222                                    }
223                                    finally {
224                                            inputStream.close();
225                                    }
226                            }
227                    }
228                    catch (Exception e) {
229                            if (_log.isWarnEnabled()) {
230                                    _log.warn(e, e);
231                            }
232                    }
233                    finally {
234                            PortalSecurityManagerThreadLocal.setEnabled(enabled);
235                    }
236    
237                    return properties;
238            }
239    
240            private static Log _log = LogFactoryUtil.getLog(LanguageResources.class);
241    
242            private static Locale _blankLocale = new Locale(StringPool.BLANK);
243            private static String[] _configNames;
244            private static Map<Locale, Map<String, String>> _languageMaps =
245                    new ConcurrentHashMap<Locale, Map<String, String>>(64);
246    
247    }