001    /**
002     * Copyright (c) 2000-present 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.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
018    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
019    import com.liferay.portal.kernel.json.JSONObject;
020    import com.liferay.portal.kernel.language.LanguageUtil;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
024    import com.liferay.portal.kernel.settings.Settings;
025    import com.liferay.portal.kernel.util.ArrayUtil;
026    import com.liferay.portal.kernel.util.LocaleUtil;
027    import com.liferay.portal.kernel.util.Localization;
028    import com.liferay.portal.kernel.util.ParamUtil;
029    import com.liferay.portal.kernel.util.PrefsParamUtil;
030    import com.liferay.portal.kernel.util.StringBundler;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.kernel.util.Tuple;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.kernel.xml.Document;
036    import com.liferay.portal.kernel.xml.Element;
037    import com.liferay.portal.language.LanguageResources;
038    import com.liferay.util.ContentUtil;
039    
040    import java.util.HashMap;
041    import java.util.Locale;
042    import java.util.Map;
043    import java.util.ResourceBundle;
044    
045    import javax.portlet.PortletPreferences;
046    import javax.portlet.PortletRequest;
047    
048    import javax.servlet.http.HttpServletRequest;
049    
050    import javax.xml.stream.XMLInputFactory;
051    import javax.xml.stream.XMLOutputFactory;
052    import javax.xml.stream.XMLStreamConstants;
053    import javax.xml.stream.XMLStreamException;
054    import javax.xml.stream.XMLStreamReader;
055    import javax.xml.stream.XMLStreamWriter;
056    
057    import org.apache.commons.collections.map.ReferenceMap;
058    
059    /**
060     * @author Alexander Chow
061     * @author Jorge Ferrer
062     * @author Mauro Mariuzzo
063     * @author Julio Camarero
064     * @author Brian Wing Shun Chan
065     * @author Connor McKay
066     */
067    @DoPrivileged
068    public class LocalizationImpl implements Localization {
069    
070            @Override
071            public Object deserialize(JSONObject jsonObject) {
072                    Locale[] locales = LanguageUtil.getAvailableLocales();
073    
074                    Map<Locale, String> map = new HashMap<Locale, String>();
075    
076                    for (Locale locale : locales) {
077                            String languageId = LocaleUtil.toLanguageId(locale);
078    
079                            String value = jsonObject.getString(languageId);
080    
081                            if (Validator.isNotNull(value)) {
082                                    map.put(locale, value);
083                            }
084                    }
085    
086                    return map;
087            }
088    
089            @Override
090            public String[] getAvailableLanguageIds(Document document) {
091                    String attributeValue = _getRootAttributeValue(
092                            document, _AVAILABLE_LOCALES, StringPool.BLANK);
093    
094                    return StringUtil.split(attributeValue);
095            }
096    
097            @Override
098            public String[] getAvailableLanguageIds(String xml) {
099                    String attributeValue = _getRootAttributeValue(
100                            xml, _AVAILABLE_LOCALES, StringPool.BLANK);
101    
102                    return StringUtil.split(attributeValue);
103            }
104    
105            @Override
106            public Locale getDefaultImportLocale(
107                    String className, long classPK, Locale contentDefaultLocale,
108                    Locale[] contentAvailableLocales) {
109    
110                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
111    
112                    if (ArrayUtil.contains(availableLocales, contentDefaultLocale)) {
113                            return contentDefaultLocale;
114                    }
115    
116                    Locale defaultLocale = LocaleUtil.getDefault();
117    
118                    if (ArrayUtil.contains(contentAvailableLocales, defaultLocale)) {
119                            return defaultLocale;
120                    }
121    
122                    for (Locale contentAvailableLocale : contentAvailableLocales) {
123                            if (ArrayUtil.contains(availableLocales, contentAvailableLocale)) {
124                                    return contentAvailableLocale;
125                            }
126                    }
127    
128                    if (_log.isWarnEnabled()) {
129                            StringBundler sb = new StringBundler(9);
130    
131                            sb.append("Language ");
132                            sb.append(LocaleUtil.toLanguageId(contentDefaultLocale));
133                            sb.append(" is missing for ");
134                            sb.append(className);
135                            sb.append(" with primary key ");
136                            sb.append(classPK);
137                            sb.append(". Setting default language to ");
138                            sb.append(LocaleUtil.toLanguageId(defaultLocale));
139                            sb.append(".");
140    
141                            _log.warn(sb.toString());
142                    }
143    
144                    return defaultLocale;
145            }
146    
147            @Override
148            public String getDefaultLanguageId(Document document) {
149                    return getDefaultLanguageId(document, LocaleUtil.getDefault());
150            }
151    
152            @Override
153            public String getDefaultLanguageId(
154                    Document document, Locale defaultLocale) {
155    
156                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
157    
158                    return _getRootAttributeValue(
159                            document, _DEFAULT_LOCALE, defaultLanguageId);
160            }
161    
162            @Override
163            public String getDefaultLanguageId(String xml) {
164                    return getDefaultLanguageId(xml, LocaleUtil.getDefault());
165            }
166    
167            @Override
168            public String getDefaultLanguageId(String xml, Locale defaultLocale) {
169                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
170    
171                    return _getRootAttributeValue(xml, _DEFAULT_LOCALE, defaultLanguageId);
172            }
173    
174            @Override
175            public String getLocalization(String xml, String requestedLanguageId) {
176                    return getLocalization(xml, requestedLanguageId, true);
177            }
178    
179            @Override
180            public String getLocalization(
181                    String xml, String requestedLanguageId, boolean useDefault) {
182    
183                    return getLocalization(
184                            xml, requestedLanguageId, useDefault, StringPool.BLANK);
185            }
186    
187            @Override
188            public String getLocalization(
189                    String xml, String requestedLanguageId, boolean useDefault,
190                    String defaultValue) {
191    
192                    String systemDefaultLanguageId = LocaleUtil.toLanguageId(
193                            LocaleUtil.getDefault());
194    
195                    if (!Validator.isXml(xml)) {
196                            if (useDefault ||
197                                    requestedLanguageId.equals(systemDefaultLanguageId)) {
198    
199                                    return xml;
200                            }
201                            else {
202                                    return defaultValue;
203                            }
204                    }
205    
206                    String value = _getCachedValue(xml, requestedLanguageId, useDefault);
207    
208                    if (value != null) {
209                            return value;
210                    }
211    
212                    String priorityLanguageId = null;
213    
214                    Locale requestedLocale = LocaleUtil.fromLanguageId(requestedLanguageId);
215    
216                    if (useDefault &&
217                            LanguageUtil.isDuplicateLanguageCode(
218                                    requestedLocale.getLanguage())) {
219    
220                            Locale priorityLocale = LanguageUtil.getLocale(
221                                    requestedLocale.getLanguage());
222    
223                            if (!requestedLanguageId.equals(priorityLanguageId)) {
224                                    priorityLanguageId = LocaleUtil.toLanguageId(priorityLocale);
225                            }
226                    }
227    
228                    XMLStreamReader xmlStreamReader = null;
229    
230                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
231    
232                    ClassLoader contextClassLoader =
233                            ClassLoaderUtil.getContextClassLoader();
234    
235                    try {
236                            if (contextClassLoader != portalClassLoader) {
237                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
238                            }
239    
240                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
241    
242                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
243                                    new UnsyncStringReader(xml));
244    
245                            String defaultLanguageId = StringPool.BLANK;
246    
247                            // Skip root node
248    
249                            if (xmlStreamReader.hasNext()) {
250                                    xmlStreamReader.nextTag();
251    
252                                    defaultLanguageId = xmlStreamReader.getAttributeValue(
253                                            null, _DEFAULT_LOCALE);
254    
255                                    if (Validator.isNull(defaultLanguageId)) {
256                                            defaultLanguageId = systemDefaultLanguageId;
257                                    }
258                            }
259    
260                            // Find specified language and/or default language
261    
262                            String priorityValue = null;
263                            String defaultLocalizationValue = null;
264    
265                            while (xmlStreamReader.hasNext()) {
266                                    int event = xmlStreamReader.next();
267    
268                                    if (event == XMLStreamConstants.START_ELEMENT) {
269                                            String languageId = xmlStreamReader.getAttributeValue(
270                                                    null, _LANGUAGE_ID);
271    
272                                            if (Validator.isNull(languageId)) {
273                                                    languageId = defaultLanguageId;
274                                            }
275    
276                                            if (languageId.equals(defaultLanguageId) ||
277                                                    languageId.equals(priorityLanguageId) ||
278                                                    languageId.equals(requestedLanguageId)) {
279    
280                                                    String text = xmlStreamReader.getElementText();
281    
282                                                    if (languageId.equals(defaultLanguageId)) {
283                                                            defaultLocalizationValue = text;
284                                                    }
285    
286                                                    if (languageId.equals(priorityLanguageId)) {
287                                                            priorityValue = text;
288                                                    }
289    
290                                                    if (languageId.equals(requestedLanguageId)) {
291                                                            value = text;
292                                                    }
293    
294                                                    if (Validator.isNotNull(value)) {
295                                                            break;
296                                                    }
297                                            }
298                                    }
299                                    else if (event == XMLStreamConstants.END_DOCUMENT) {
300                                            break;
301                                    }
302                            }
303    
304                            if (useDefault && Validator.isNotNull(priorityLanguageId) &&
305                                    Validator.isNull(value) && Validator.isNotNull(priorityValue)) {
306    
307                                    value = priorityValue;
308                            }
309    
310                            if (useDefault && Validator.isNull(value)) {
311                                    value = defaultLocalizationValue;
312                            }
313    
314                            if (Validator.isNull(value)) {
315                                    value = defaultValue;
316                            }
317                    }
318                    catch (Exception e) {
319                            if (_log.isWarnEnabled()) {
320                                    _log.warn(e, e);
321                            }
322                    }
323                    finally {
324                            if (contextClassLoader != portalClassLoader) {
325                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
326                            }
327    
328                            if (xmlStreamReader != null) {
329                                    try {
330                                            xmlStreamReader.close();
331                                    }
332                                    catch (Exception e) {
333                                    }
334                            }
335                    }
336    
337                    _setCachedValue(xml, requestedLanguageId, useDefault, value);
338    
339                    return value;
340            }
341    
342            @Override
343            public Map<Locale, String> getLocalizationMap(
344                    HttpServletRequest request, String parameter) {
345    
346                    Locale[] locales = LanguageUtil.getAvailableLocales();
347    
348                    Map<Locale, String> map = new HashMap<Locale, String>();
349    
350                    for (Locale locale : locales) {
351                            String localizedParameter = getLocalizedName(
352                                    parameter, LocaleUtil.toLanguageId(locale));
353    
354                            map.put(locale, ParamUtil.getString(request, localizedParameter));
355                    }
356    
357                    return map;
358            }
359    
360            @Override
361            public Map<Locale, String> getLocalizationMap(
362                    PortletPreferences preferences, String preferenceName) {
363    
364                    return getLocalizationMap(preferences, preferenceName, null);
365            }
366    
367            @Override
368            public Map<Locale, String> getLocalizationMap(
369                    PortletPreferences preferences, String preferenceName,
370                    String propertyName) {
371    
372                    Locale[] locales = LanguageUtil.getAvailableLocales();
373    
374                    Map<Locale, String> map = new HashMap<Locale, String>();
375    
376                    for (Locale locale : locales) {
377                            String localizedPreference = getLocalizedName(
378                                    preferenceName, LocaleUtil.toLanguageId(locale));
379    
380                            map.put(
381                                    locale,
382                                    preferences.getValue(localizedPreference, StringPool.BLANK));
383                    }
384    
385                    if (Validator.isNull(propertyName)) {
386                            return map;
387                    }
388    
389                    Locale defaultLocale = LocaleUtil.getSiteDefault();
390    
391                    String defaultValue = map.get(defaultLocale);
392    
393                    if (Validator.isNotNull(defaultValue)) {
394                            return map;
395                    }
396    
397                    map.put(defaultLocale, ContentUtil.get(PropsUtil.get(propertyName)));
398    
399                    return map;
400            }
401    
402            @Override
403            public Map<Locale, String> getLocalizationMap(
404                    PortletRequest portletRequest, String parameter) {
405    
406                    return getLocalizationMap(
407                            portletRequest, parameter, new HashMap<Locale, String>());
408            }
409    
410            @Override
411            public Map<Locale, String> getLocalizationMap(
412                    PortletRequest portletRequest, String parameter,
413                    Map<Locale, String> defaultValues) {
414    
415                    Locale[] locales = LanguageUtil.getAvailableLocales();
416    
417                    Map<Locale, String> map = new HashMap<Locale, String>();
418    
419                    for (Locale locale : locales) {
420                            String localizedParameter = getLocalizedName(
421                                    parameter, LocaleUtil.toLanguageId(locale));
422    
423                            map.put(
424                                    locale,
425                                    ParamUtil.getString(
426                                            portletRequest, localizedParameter,
427                                            defaultValues.get(locale)));
428                    }
429    
430                    return map;
431            }
432    
433            @Override
434            public Map<Locale, String> getLocalizationMap(String xml) {
435                    return getLocalizationMap(xml, false);
436            }
437    
438            @Override
439            public Map<Locale, String> getLocalizationMap(
440                    String xml, boolean useDefault) {
441    
442                    Locale[] locales = LanguageUtil.getAvailableLocales();
443    
444                    Map<Locale, String> map = new HashMap<Locale, String>();
445    
446                    for (Locale locale : locales) {
447                            String languageId = LocaleUtil.toLanguageId(locale);
448    
449                            String value = getLocalization(xml, languageId, useDefault);
450    
451                            if (Validator.isNotNull(value)) {
452                                    map.put(locale, value);
453                            }
454                    }
455    
456                    return map;
457            }
458    
459            @Override
460            public Map<Locale, String> getLocalizationMap(
461                    String bundleName, ClassLoader classLoader, String key,
462                    boolean includeBetaLocales) {
463    
464                    if (key == null) {
465                            return null;
466                    }
467    
468                    Map<Locale, String> map = new HashMap<Locale, String>();
469    
470                    Locale defaultLocale = LocaleUtil.getDefault();
471    
472                    String defaultValue = _getLocalization(
473                            bundleName, defaultLocale, classLoader, key, key);
474    
475                    map.put(defaultLocale, defaultValue);
476    
477                    Locale[] locales = null;
478    
479                    if (includeBetaLocales) {
480                            locales = LanguageUtil.getAvailableLocales();
481                    }
482                    else {
483                            locales = LanguageUtil.getSupportedLocales();
484                    }
485    
486                    for (Locale locale : locales) {
487                            if (locale.equals(defaultLocale)) {
488                                    continue;
489                            }
490    
491                            String value = _getLocalization(
492                                    bundleName, locale, classLoader, key, null);
493    
494                            if (Validator.isNotNull(value) && !value.equals(defaultValue)) {
495                                    map.put(locale, value);
496                            }
497                    }
498    
499                    return map;
500            }
501    
502            @Override
503            public Map<Locale, String> getLocalizationMap(
504                    String[] languageIds, String[] values) {
505    
506                    Map<Locale, String> map = new HashMap<Locale, String>();
507    
508                    for (int i = 0; i < values.length; i++) {
509                            Locale locale = LocaleUtil.fromLanguageId(languageIds[i]);
510    
511                            map.put(locale, values[i]);
512                    }
513    
514                    return map;
515            }
516    
517            @Override
518            public String getLocalizationXmlFromPreferences(
519                    PortletPreferences preferences, PortletRequest portletRequest,
520                    String parameter) {
521    
522                    return getLocalizationXmlFromPreferences(
523                            preferences, portletRequest, parameter, null, null);
524            }
525    
526            @Override
527            public String getLocalizationXmlFromPreferences(
528                    PortletPreferences preferences, PortletRequest portletRequest,
529                    String parameter, String defaultValue) {
530    
531                    return getLocalizationXmlFromPreferences(
532                            preferences, portletRequest, parameter, defaultValue, null);
533            }
534    
535            @Override
536            public String getLocalizationXmlFromPreferences(
537                    PortletPreferences preferences, PortletRequest portletRequest,
538                    String parameter, String prefix, String defaultValue) {
539    
540                    String xml = null;
541    
542                    Locale[] locales = LanguageUtil.getAvailableLocales();
543                    Locale defaultLocale = LocaleUtil.getDefault();
544                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
545    
546                    for (Locale locale : locales) {
547                            String languageId = LocaleUtil.toLanguageId(locale);
548    
549                            String localizedKey = getLocalizedName(parameter, languageId);
550    
551                            String prefixedLocalizedKey = localizedKey;
552    
553                            if (Validator.isNotNull(prefix)) {
554                                    prefixedLocalizedKey = prefix + "--" + localizedKey + "--";
555                            }
556    
557                            String value = ParamUtil.getString(
558                                    portletRequest, prefixedLocalizedKey,
559                                    preferences.getValue(localizedKey, null));
560    
561                            if (value != null) {
562                                    xml = updateLocalization(xml, parameter, value, languageId);
563                            }
564                    }
565    
566                    if (getLocalization(xml, defaultLanguageId, true, null) == null) {
567                            String oldValue = PrefsParamUtil.getString(
568                                    preferences, portletRequest, parameter, defaultValue);
569    
570                            if (Validator.isNotNull(oldValue)) {
571                                    xml = updateLocalization(xml, parameter, oldValue);
572                            }
573                    }
574    
575                    return xml;
576            }
577    
578            @Override
579            public String getLocalizedName(String name, String languageId) {
580                    return name.concat(StringPool.UNDERLINE).concat(languageId);
581            }
582    
583            @Override
584            public Map<Locale, String> getLocalizedParameter(
585                    PortletRequest portletRequest, String parameter) {
586    
587                    return getLocalizationMap(portletRequest, parameter);
588            }
589    
590            @Override
591            public String getPreferencesKey(String key, String languageId) {
592                    String defaultLanguageId = LocaleUtil.toLanguageId(
593                            LocaleUtil.getDefault());
594    
595                    if (!languageId.equals(defaultLanguageId)) {
596                            key = getLocalizedName(key, languageId);
597                    }
598    
599                    return key;
600            }
601    
602            @Override
603            public String getPreferencesValue(
604                    PortletPreferences preferences, String key, String languageId) {
605    
606                    return getPreferencesValue(preferences, key, languageId, true);
607            }
608    
609            @Override
610            public String getPreferencesValue(
611                    PortletPreferences preferences, String key, String languageId,
612                    boolean useDefault) {
613    
614                    String localizedKey = getLocalizedName(key, languageId);
615    
616                    String value = preferences.getValue(localizedKey, StringPool.BLANK);
617    
618                    if (useDefault && Validator.isNull(value)) {
619                            value = preferences.getValue(
620                                    _getDefaultLocalizedName(key), StringPool.BLANK);
621    
622                            if (Validator.isNull(value)) {
623                                    value = preferences.getValue(key, StringPool.BLANK);
624                            }
625                    }
626    
627                    return value;
628            }
629    
630            @Override
631            public String[] getPreferencesValues(
632                    PortletPreferences preferences, String key, String languageId) {
633    
634                    return getPreferencesValues(preferences, key, languageId, true);
635            }
636    
637            @Override
638            public String[] getPreferencesValues(
639                    PortletPreferences preferences, String key, String languageId,
640                    boolean useDefault) {
641    
642                    String localizedKey = getLocalizedName(key, languageId);
643    
644                    String[] values = preferences.getValues(localizedKey, new String[0]);
645    
646                    if (useDefault && ArrayUtil.isEmpty(values)) {
647                            values = preferences.getValues(
648                                    _getDefaultLocalizedName(key), new String[0]);
649    
650                            if (ArrayUtil.isEmpty(values)) {
651                                    values = preferences.getValues(key, new String[0]);
652                            }
653                    }
654    
655                    return values;
656            }
657    
658            @Override
659            public String getSettingsValue(
660                    Settings settings, String key, String languageId) {
661    
662                    return getSettingsValue(settings, key, languageId, true);
663            }
664    
665            @Override
666            public String getSettingsValue(
667                    Settings settings, String key, String languageId, boolean useDefault) {
668    
669                    String localizedKey = getLocalizedName(key, languageId);
670    
671                    String value = settings.getValue(localizedKey, StringPool.BLANK);
672    
673                    if (useDefault && Validator.isNull(value)) {
674                            value = settings.getValue(
675                                    _getDefaultLocalizedName(key), StringPool.BLANK);
676    
677                            if (Validator.isNull(value)) {
678                                    value = settings.getValue(key, StringPool.BLANK);
679                            }
680                    }
681    
682                    return value;
683            }
684    
685            @Override
686            public String[] getSettingsValues(
687                    Settings settings, String key, String languageId) {
688    
689                    return getSettingsValues(settings, key, languageId, true);
690            }
691    
692            @Override
693            public String[] getSettingsValues(
694                    Settings settings, String key, String languageId, boolean useDefault) {
695    
696                    String localizedKey = getLocalizedName(key, languageId);
697    
698                    String[] values = settings.getValues(localizedKey, new String[0]);
699    
700                    if (useDefault && ArrayUtil.isEmpty(values)) {
701                            values = settings.getValues(
702                                    _getDefaultLocalizedName(key), new String[0]);
703    
704                            if (ArrayUtil.isEmpty(values)) {
705                                    values = settings.getValues(key, new String[0]);
706                            }
707                    }
708    
709                    return values;
710            }
711    
712            @Override
713            public String removeLocalization(
714                    String xml, String key, String requestedLanguageId) {
715    
716                    return removeLocalization(xml, key, requestedLanguageId, false);
717            }
718    
719            @Override
720            public String removeLocalization(
721                    String xml, String key, String requestedLanguageId, boolean cdata) {
722    
723                    return removeLocalization(xml, key, requestedLanguageId, cdata, true);
724            }
725    
726            @Override
727            public String removeLocalization(
728                    String xml, String key, String requestedLanguageId, boolean cdata,
729                    boolean localized) {
730    
731                    if (Validator.isNull(xml)) {
732                            return StringPool.BLANK;
733                    }
734    
735                    if (!Validator.isXml(xml)) {
736                            return xml;
737                    }
738    
739                    xml = _sanitizeXML(xml);
740    
741                    String systemDefaultLanguageId = LocaleUtil.toLanguageId(
742                            LocaleUtil.getDefault());
743    
744                    XMLStreamReader xmlStreamReader = null;
745                    XMLStreamWriter xmlStreamWriter = null;
746    
747                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
748    
749                    ClassLoader contextClassLoader =
750                            ClassLoaderUtil.getContextClassLoader();
751    
752                    try {
753                            if (contextClassLoader != portalClassLoader) {
754                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
755                            }
756    
757                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
758    
759                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
760                                    new UnsyncStringReader(xml));
761    
762                            String availableLocales = StringPool.BLANK;
763                            String defaultLanguageId = StringPool.BLANK;
764    
765                            // Read root node
766    
767                            if (xmlStreamReader.hasNext()) {
768                                    xmlStreamReader.nextTag();
769    
770                                    availableLocales = xmlStreamReader.getAttributeValue(
771                                            null, _AVAILABLE_LOCALES);
772                                    defaultLanguageId = xmlStreamReader.getAttributeValue(
773                                            null, _DEFAULT_LOCALE);
774    
775                                    if (Validator.isNull(defaultLanguageId)) {
776                                            defaultLanguageId = systemDefaultLanguageId;
777                                    }
778                            }
779    
780                            if ((availableLocales != null) &&
781                                    availableLocales.contains(requestedLanguageId)) {
782    
783                                    availableLocales = StringUtil.removeFromList(
784                                            availableLocales, requestedLanguageId);
785    
786                                    UnsyncStringWriter unsyncStringWriter =
787                                            new UnsyncStringWriter();
788    
789                                    XMLOutputFactory xmlOutputFactory =
790                                            XMLOutputFactory.newInstance();
791    
792                                    xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
793                                            unsyncStringWriter);
794    
795                                    xmlStreamWriter.writeStartDocument();
796                                    xmlStreamWriter.writeStartElement(_ROOT);
797    
798                                    if (localized) {
799                                            xmlStreamWriter.writeAttribute(
800                                                    _AVAILABLE_LOCALES, availableLocales);
801                                            xmlStreamWriter.writeAttribute(
802                                                    _DEFAULT_LOCALE, defaultLanguageId);
803                                    }
804    
805                                    _copyNonExempt(
806                                            xmlStreamReader, xmlStreamWriter, requestedLanguageId,
807                                            defaultLanguageId, cdata);
808    
809                                    xmlStreamWriter.writeEndElement();
810                                    xmlStreamWriter.writeEndDocument();
811    
812                                    xmlStreamWriter.close();
813                                    xmlStreamWriter = null;
814    
815                                    xml = unsyncStringWriter.toString();
816                            }
817                    }
818                    catch (Exception e) {
819                            if (_log.isWarnEnabled()) {
820                                    _log.warn(e, e);
821                            }
822                    }
823                    finally {
824                            if (contextClassLoader != portalClassLoader) {
825                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
826                            }
827    
828                            if (xmlStreamReader != null) {
829                                    try {
830                                            xmlStreamReader.close();
831                                    }
832                                    catch (Exception e) {
833                                    }
834                            }
835    
836                            if (xmlStreamWriter != null) {
837                                    try {
838                                            xmlStreamWriter.close();
839                                    }
840                                    catch (Exception e) {
841                                    }
842                            }
843                    }
844    
845                    return xml;
846            }
847    
848            @Override
849            public void setLocalizedPreferencesValues(
850                            PortletRequest portletRequest, PortletPreferences preferences,
851                            String parameter)
852                    throws Exception {
853    
854                    Map<Locale, String> map = getLocalizationMap(portletRequest, parameter);
855    
856                    for (Map.Entry<Locale, String> entry : map.entrySet()) {
857                            String languageId = LocaleUtil.toLanguageId(entry.getKey());
858                            String value = entry.getValue();
859    
860                            setPreferencesValue(preferences, parameter, languageId, value);
861                    }
862            }
863    
864            @Override
865            public void setPreferencesValue(
866                            PortletPreferences preferences, String key, String languageId,
867                            String value)
868                    throws Exception {
869    
870                    preferences.setValue(getLocalizedName(key, languageId), value);
871            }
872    
873            @Override
874            public void setPreferencesValues(
875                            PortletPreferences preferences, String key, String languageId,
876                            String[] values)
877                    throws Exception {
878    
879                    preferences.setValues(getLocalizedName(key, languageId), values);
880            }
881    
882            @Override
883            public String updateLocalization(
884                    Map<Locale, String> localizationMap, String xml, String key,
885                    String defaultLanguageId) {
886    
887                    Locale[] locales = LanguageUtil.getAvailableLocales();
888    
889                    for (Locale locale : locales) {
890                            String value = localizationMap.get(locale);
891    
892                            String languageId = LocaleUtil.toLanguageId(locale);
893    
894                            if (Validator.isNotNull(value)) {
895                                    xml = updateLocalization(
896                                            xml, key, value, languageId, defaultLanguageId);
897                            }
898                            else {
899                                    xml = removeLocalization(xml, key, languageId);
900                            }
901                    }
902    
903                    return xml;
904            }
905    
906            @Override
907            public String updateLocalization(String xml, String key, String value) {
908                    String defaultLanguageId = LocaleUtil.toLanguageId(
909                            LocaleUtil.getDefault());
910    
911                    return updateLocalization(
912                            xml, key, value, defaultLanguageId, defaultLanguageId);
913            }
914    
915            @Override
916            public String updateLocalization(
917                    String xml, String key, String value, String requestedLanguageId) {
918    
919                    String defaultLanguageId = LocaleUtil.toLanguageId(
920                            LocaleUtil.getDefault());
921    
922                    return updateLocalization(
923                            xml, key, value, requestedLanguageId, defaultLanguageId);
924            }
925    
926            @Override
927            public String updateLocalization(
928                    String xml, String key, String value, String requestedLanguageId,
929                    String defaultLanguageId) {
930    
931                    return updateLocalization(
932                            xml, key, value, requestedLanguageId, defaultLanguageId, false);
933            }
934    
935            @Override
936            public String updateLocalization(
937                    String xml, String key, String value, String requestedLanguageId,
938                    String defaultLanguageId, boolean cdata) {
939    
940                    return updateLocalization(
941                            xml, key, value, requestedLanguageId, defaultLanguageId, cdata,
942                            true);
943            }
944    
945            @Override
946            public String updateLocalization(
947                    String xml, String key, String value, String requestedLanguageId,
948                    String defaultLanguageId, boolean cdata, boolean localized) {
949    
950                    xml = _sanitizeXML(xml);
951    
952                    XMLStreamReader xmlStreamReader = null;
953                    XMLStreamWriter xmlStreamWriter = null;
954    
955                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
956    
957                    ClassLoader contextClassLoader =
958                            ClassLoaderUtil.getContextClassLoader();
959    
960                    try {
961                            if (contextClassLoader != portalClassLoader) {
962                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
963                            }
964    
965                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
966    
967                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
968                                    new UnsyncStringReader(xml));
969    
970                            String availableLocales = StringPool.BLANK;
971    
972                            // Read root node
973    
974                            if (xmlStreamReader.hasNext()) {
975                                    xmlStreamReader.nextTag();
976    
977                                    availableLocales = xmlStreamReader.getAttributeValue(
978                                            null, _AVAILABLE_LOCALES);
979    
980                                    if (Validator.isNull(availableLocales)) {
981                                            availableLocales = defaultLanguageId;
982                                    }
983    
984                                    if (!availableLocales.contains(requestedLanguageId)) {
985                                            availableLocales = StringUtil.add(
986                                                    availableLocales, requestedLanguageId,
987                                                    StringPool.COMMA);
988                                    }
989                            }
990    
991                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
992    
993                            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
994    
995                            xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
996                                    unsyncStringWriter);
997    
998                            xmlStreamWriter.writeStartDocument();
999                            xmlStreamWriter.writeStartElement(_ROOT);
1000    
1001                            if (localized) {
1002                                    xmlStreamWriter.writeAttribute(
1003                                            _AVAILABLE_LOCALES, availableLocales);
1004                                    xmlStreamWriter.writeAttribute(
1005                                            _DEFAULT_LOCALE, defaultLanguageId);
1006                            }
1007    
1008                            _copyNonExempt(
1009                                    xmlStreamReader, xmlStreamWriter, requestedLanguageId,
1010                                    defaultLanguageId, cdata);
1011    
1012                            xmlStreamWriter.writeStartElement(key);
1013    
1014                            if (localized) {
1015                                    xmlStreamWriter.writeAttribute(
1016                                            _LANGUAGE_ID, requestedLanguageId);
1017                            }
1018    
1019                            if (cdata) {
1020                                    xmlStreamWriter.writeCData(value);
1021                            }
1022                            else {
1023                                    xmlStreamWriter.writeCharacters(value);
1024                            }
1025    
1026                            xmlStreamWriter.writeEndElement();
1027                            xmlStreamWriter.writeEndElement();
1028                            xmlStreamWriter.writeEndDocument();
1029    
1030                            xmlStreamWriter.close();
1031                            xmlStreamWriter = null;
1032    
1033                            xml = unsyncStringWriter.toString();
1034                    }
1035                    catch (Exception e) {
1036                            if (_log.isWarnEnabled()) {
1037                                    _log.warn(e, e);
1038                            }
1039                    }
1040                    finally {
1041                            if (contextClassLoader != portalClassLoader) {
1042                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
1043                            }
1044    
1045                            if (xmlStreamReader != null) {
1046                                    try {
1047                                            xmlStreamReader.close();
1048                                    }
1049                                    catch (Exception e) {
1050                                    }
1051                            }
1052    
1053                            if (xmlStreamWriter != null) {
1054                                    try {
1055                                            xmlStreamWriter.close();
1056                                    }
1057                                    catch (Exception e) {
1058                                    }
1059                            }
1060                    }
1061    
1062                    return xml;
1063            }
1064    
1065            private void _copyNonExempt(
1066                            XMLStreamReader xmlStreamReader, XMLStreamWriter xmlStreamWriter,
1067                            String exemptLanguageId, String defaultLanguageId, boolean cdata)
1068                    throws XMLStreamException {
1069    
1070                    while (xmlStreamReader.hasNext()) {
1071                            int event = xmlStreamReader.next();
1072    
1073                            if (event == XMLStreamConstants.START_ELEMENT) {
1074                                    String languageId = xmlStreamReader.getAttributeValue(
1075                                            null, _LANGUAGE_ID);
1076    
1077                                    if (Validator.isNull(languageId)) {
1078                                            languageId = defaultLanguageId;
1079                                    }
1080    
1081                                    if (!languageId.equals(exemptLanguageId)) {
1082                                            xmlStreamWriter.writeStartElement(
1083                                                    xmlStreamReader.getLocalName());
1084                                            xmlStreamWriter.writeAttribute(_LANGUAGE_ID, languageId);
1085    
1086                                            while (xmlStreamReader.hasNext()) {
1087                                                    event = xmlStreamReader.next();
1088    
1089                                                    if ((event == XMLStreamConstants.CHARACTERS) ||
1090                                                            (event == XMLStreamConstants.CDATA)) {
1091    
1092                                                            String text = xmlStreamReader.getText();
1093    
1094                                                            if (cdata) {
1095                                                                    xmlStreamWriter.writeCData(text);
1096                                                            }
1097                                                            else {
1098                                                                    xmlStreamWriter.writeCharacters(
1099                                                                            xmlStreamReader.getText());
1100                                                            }
1101    
1102                                                            break;
1103                                                    }
1104                                                    else if (event == XMLStreamConstants.END_ELEMENT) {
1105                                                            break;
1106                                                    }
1107                                            }
1108    
1109                                            xmlStreamWriter.writeEndElement();
1110                                    }
1111                            }
1112                            else if (event == XMLStreamConstants.END_DOCUMENT) {
1113                                    break;
1114                            }
1115                    }
1116            }
1117    
1118            private String _getCachedValue(
1119                    String xml, String requestedLanguageId, boolean useDefault) {
1120    
1121                    String value = null;
1122    
1123                    Map<Tuple, String> valueMap = _cache.get(xml);
1124    
1125                    if (valueMap != null) {
1126                            Tuple subkey = new Tuple(useDefault, requestedLanguageId);
1127    
1128                            value = valueMap.get(subkey);
1129                    }
1130    
1131                    return value;
1132            }
1133    
1134            private String _getDefaultLocalizedName(String name) {
1135                    String defaultLanguageId = LocaleUtil.toLanguageId(
1136                            LocaleUtil.getDefault());
1137    
1138                    return getLocalizedName(name, defaultLanguageId);
1139            }
1140    
1141            private String _getLocalization(
1142                    String bundleName, Locale locale, ClassLoader classLoader, String key,
1143                    String defaultValue) {
1144    
1145                    ResourceBundle resourceBundle = ResourceBundle.getBundle(
1146                            bundleName, locale, classLoader);
1147    
1148                    String value = null;
1149    
1150                    if (resourceBundle.containsKey(key)) {
1151                            try {
1152                                    value = resourceBundle.getString(key);
1153    
1154                                    value = new String(
1155                                            value.getBytes(StringPool.ISO_8859_1), StringPool.UTF8);
1156                            }
1157    
1158                            catch (Exception e) {
1159                            }
1160                    }
1161    
1162                    if (Validator.isNotNull(value)) {
1163                            value = LanguageResources.fixValue(value);
1164                    }
1165                    else {
1166                            value = LanguageUtil.get(locale, key, defaultValue);
1167                    }
1168    
1169                    return value;
1170            }
1171    
1172            private String _getRootAttributeValue(
1173                    Document document, String name, String defaultValue) {
1174    
1175                    Element rootElement = document.getRootElement();
1176    
1177                    return rootElement.attributeValue(name, defaultValue);
1178            }
1179    
1180            private String _getRootAttributeValue(
1181                    String xml, String name, String defaultValue) {
1182    
1183                    String value = null;
1184    
1185                    XMLStreamReader xmlStreamReader = null;
1186    
1187                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
1188    
1189                    ClassLoader contextClassLoader =
1190                            ClassLoaderUtil.getContextClassLoader();
1191    
1192                    try {
1193                            if (contextClassLoader != portalClassLoader) {
1194                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
1195                            }
1196    
1197                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
1198    
1199                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
1200                                    new UnsyncStringReader(xml));
1201    
1202                            if (xmlStreamReader.hasNext()) {
1203                                    xmlStreamReader.nextTag();
1204    
1205                                    value = xmlStreamReader.getAttributeValue(null, name);
1206                            }
1207                    }
1208                    catch (Exception e) {
1209                            if (_log.isWarnEnabled()) {
1210                                    _log.warn(e, e);
1211                            }
1212                    }
1213                    finally {
1214                            if (contextClassLoader != portalClassLoader) {
1215                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
1216                            }
1217    
1218                            if (xmlStreamReader != null) {
1219                                    try {
1220                                            xmlStreamReader.close();
1221                                    }
1222                                    catch (Exception e) {
1223                                    }
1224                            }
1225                    }
1226    
1227                    if (Validator.isNull(value)) {
1228                            value = defaultValue;
1229                    }
1230    
1231                    return value;
1232            }
1233    
1234            private String _sanitizeXML(String xml) {
1235                    if (Validator.isNull(xml) || !xml.contains("<root")) {
1236                            xml = _EMPTY_ROOT_NODE;
1237                    }
1238    
1239                    return xml;
1240            }
1241    
1242            private void _setCachedValue(
1243                    String xml, String requestedLanguageId, boolean useDefault,
1244                    String value) {
1245    
1246                    if (Validator.isNotNull(xml) && !xml.equals(_EMPTY_ROOT_NODE)) {
1247                            synchronized (_cache) {
1248                                    Map<Tuple, String> map = _cache.get(xml);
1249    
1250                                    if (map == null) {
1251                                            map = new HashMap<Tuple, String>();
1252                                    }
1253    
1254                                    Tuple subkey = new Tuple(useDefault, requestedLanguageId);
1255    
1256                                    map.put(subkey, value);
1257    
1258                                    _cache.put(xml, map);
1259                            }
1260                    }
1261            }
1262    
1263            private static final String _AVAILABLE_LOCALES = "available-locales";
1264    
1265            private static final String _DEFAULT_LOCALE = "default-locale";
1266    
1267            private static final String _EMPTY_ROOT_NODE = "<root />";
1268    
1269            private static final String _LANGUAGE_ID = "language-id";
1270    
1271            private static final String _ROOT = "root";
1272    
1273            private static Log _log = LogFactoryUtil.getLog(LocalizationImpl.class);
1274    
1275            private Map<String, Map<Tuple, String>> _cache = new ReferenceMap(
1276                    ReferenceMap.SOFT, ReferenceMap.HARD);
1277    
1278    }