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                    Locale[] locales = LanguageUtil.getAvailableLocales();
407    
408                    Map<Locale, String> map = new HashMap<Locale, String>();
409    
410                    for (Locale locale : locales) {
411                            String localizedParameter = getLocalizedName(
412                                    parameter, LocaleUtil.toLanguageId(locale));
413    
414                            map.put(
415                                    locale,
416                                    ParamUtil.getString(portletRequest, localizedParameter));
417                    }
418    
419                    return map;
420            }
421    
422            @Override
423            public Map<Locale, String> getLocalizationMap(String xml) {
424                    return getLocalizationMap(xml, false);
425            }
426    
427            @Override
428            public Map<Locale, String> getLocalizationMap(
429                    String xml, boolean useDefault) {
430    
431                    Locale[] locales = LanguageUtil.getAvailableLocales();
432    
433                    Map<Locale, String> map = new HashMap<Locale, String>();
434    
435                    for (Locale locale : locales) {
436                            String languageId = LocaleUtil.toLanguageId(locale);
437    
438                            String value = getLocalization(xml, languageId, useDefault);
439    
440                            if (Validator.isNotNull(value)) {
441                                    map.put(locale, value);
442                            }
443                    }
444    
445                    return map;
446            }
447    
448            @Override
449            public Map<Locale, String> getLocalizationMap(
450                    String bundleName, ClassLoader classLoader, String key,
451                    boolean includeBetaLocales) {
452    
453                    if (key == null) {
454                            return null;
455                    }
456    
457                    Map<Locale, String> map = new HashMap<Locale, String>();
458    
459                    Locale defaultLocale = LocaleUtil.getDefault();
460    
461                    String defaultValue = _getLocalization(
462                            bundleName, defaultLocale, classLoader, key, key);
463    
464                    map.put(defaultLocale, defaultValue);
465    
466                    Locale[] locales = null;
467    
468                    if (includeBetaLocales) {
469                            locales = LanguageUtil.getAvailableLocales();
470                    }
471                    else {
472                            locales = LanguageUtil.getSupportedLocales();
473                    }
474    
475                    for (Locale locale : locales) {
476                            if (locale.equals(defaultLocale)) {
477                                    continue;
478                            }
479    
480                            String value = _getLocalization(
481                                    bundleName, locale, classLoader, key, null);
482    
483                            if (Validator.isNotNull(value) && !value.equals(defaultValue)) {
484                                    map.put(locale, value);
485                            }
486                    }
487    
488                    return map;
489            }
490    
491            @Override
492            public Map<Locale, String> getLocalizationMap(
493                    String[] languageIds, String[] values) {
494    
495                    Map<Locale, String> map = new HashMap<Locale, String>();
496    
497                    for (int i = 0; i < values.length; i++) {
498                            Locale locale = LocaleUtil.fromLanguageId(languageIds[i]);
499    
500                            map.put(locale, values[i]);
501                    }
502    
503                    return map;
504            }
505    
506            @Override
507            public String getLocalizationXmlFromPreferences(
508                    PortletPreferences preferences, PortletRequest portletRequest,
509                    String parameter) {
510    
511                    return getLocalizationXmlFromPreferences(
512                            preferences, portletRequest, parameter, null, null);
513            }
514    
515            @Override
516            public String getLocalizationXmlFromPreferences(
517                    PortletPreferences preferences, PortletRequest portletRequest,
518                    String parameter, String defaultValue) {
519    
520                    return getLocalizationXmlFromPreferences(
521                            preferences, portletRequest, parameter, defaultValue, null);
522            }
523    
524            @Override
525            public String getLocalizationXmlFromPreferences(
526                    PortletPreferences preferences, PortletRequest portletRequest,
527                    String parameter, String prefix, String defaultValue) {
528    
529                    String xml = null;
530    
531                    Locale[] locales = LanguageUtil.getAvailableLocales();
532                    Locale defaultLocale = LocaleUtil.getDefault();
533                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
534    
535                    for (Locale locale : locales) {
536                            String languageId = LocaleUtil.toLanguageId(locale);
537    
538                            String localizedParameter = getLocalizedName(parameter, languageId);
539    
540                            String prefixedLocalizedParameter = localizedParameter;
541    
542                            if (Validator.isNotNull(prefix)) {
543                                    prefixedLocalizedParameter =
544                                            prefix + "--" + localizedParameter + "--";
545                            }
546    
547                            String value = ParamUtil.getString(
548                                    portletRequest, prefixedLocalizedParameter,
549                                    preferences.getValue(localizedParameter, null));
550    
551                            if (value != null) {
552                                    xml = updateLocalization(xml, parameter, value, languageId);
553                            }
554                    }
555    
556                    if (getLocalization(xml, defaultLanguageId, true, null) == null) {
557                            String oldValue = PrefsParamUtil.getString(
558                                    preferences, portletRequest, parameter, defaultValue);
559    
560                            if (Validator.isNotNull(oldValue)) {
561                                    xml = updateLocalization(xml, parameter, oldValue);
562                            }
563                    }
564    
565                    return xml;
566            }
567    
568            @Override
569            public String getLocalizedName(String name, String languageId) {
570                    return name.concat(StringPool.UNDERLINE).concat(languageId);
571            }
572    
573            @Override
574            public Map<Locale, String> getLocalizedParameter(
575                    PortletRequest portletRequest, String parameter) {
576    
577                    return getLocalizationMap(portletRequest, parameter);
578            }
579    
580            @Override
581            public String getPreferencesKey(String key, String languageId) {
582                    String defaultLanguageId = LocaleUtil.toLanguageId(
583                            LocaleUtil.getDefault());
584    
585                    if (!languageId.equals(defaultLanguageId)) {
586                            key = getLocalizedName(key, languageId);
587                    }
588    
589                    return key;
590            }
591    
592            @Override
593            public String getPreferencesValue(
594                    PortletPreferences preferences, String key, String languageId) {
595    
596                    return getPreferencesValue(preferences, key, languageId, true);
597            }
598    
599            @Override
600            public String getPreferencesValue(
601                    PortletPreferences preferences, String key, String languageId,
602                    boolean useDefault) {
603    
604                    String localizedKey = getPreferencesKey(key, languageId);
605    
606                    String value = preferences.getValue(localizedKey, StringPool.BLANK);
607    
608                    if (useDefault && Validator.isNull(value)) {
609                            value = preferences.getValue(key, StringPool.BLANK);
610                    }
611    
612                    return value;
613            }
614    
615            @Override
616            public String[] getPreferencesValues(
617                    PortletPreferences preferences, String key, String languageId) {
618    
619                    return getPreferencesValues(preferences, key, languageId, true);
620            }
621    
622            @Override
623            public String[] getPreferencesValues(
624                    PortletPreferences preferences, String key, String languageId,
625                    boolean useDefault) {
626    
627                    String localizedKey = getPreferencesKey(key, languageId);
628    
629                    String[] values = preferences.getValues(localizedKey, new String[0]);
630    
631                    if (useDefault && ArrayUtil.isEmpty(values)) {
632                            values = preferences.getValues(key, new String[0]);
633                    }
634    
635                    return values;
636            }
637    
638            @Override
639            public String getSettingsValue(
640                    Settings settings, String key, String languageId) {
641    
642                    return getSettingsValue(settings, key, languageId, true);
643            }
644    
645            @Override
646            public String getSettingsValue(
647                    Settings settings, String key, String languageId, boolean useDefault) {
648    
649                    String localizedKey = getPreferencesKey(key, languageId);
650    
651                    String value = settings.getValue(localizedKey, StringPool.BLANK);
652    
653                    if (useDefault && Validator.isNull(value)) {
654                            value = settings.getValue(key, StringPool.BLANK);
655                    }
656    
657                    return value;
658            }
659    
660            @Override
661            public String[] getSettingsValues(
662                    Settings settings, String key, String languageId) {
663    
664                    return getSettingsValues(settings, key, languageId, true);
665            }
666    
667            @Override
668            public String[] getSettingsValues(
669                    Settings settings, String key, String languageId, boolean useDefault) {
670    
671                    String localizedKey = getPreferencesKey(key, languageId);
672    
673                    String[] values = settings.getValues(localizedKey, new String[0]);
674    
675                    if (useDefault && ArrayUtil.isEmpty(values)) {
676                            values = settings.getValues(key, new String[0]);
677                    }
678    
679                    return values;
680            }
681    
682            @Override
683            public String removeLocalization(
684                    String xml, String key, String requestedLanguageId) {
685    
686                    return removeLocalization(xml, key, requestedLanguageId, false);
687            }
688    
689            @Override
690            public String removeLocalization(
691                    String xml, String key, String requestedLanguageId, boolean cdata) {
692    
693                    return removeLocalization(xml, key, requestedLanguageId, cdata, true);
694            }
695    
696            @Override
697            public String removeLocalization(
698                    String xml, String key, String requestedLanguageId, boolean cdata,
699                    boolean localized) {
700    
701                    if (Validator.isNull(xml)) {
702                            return StringPool.BLANK;
703                    }
704    
705                    if (!Validator.isXml(xml)) {
706                            return xml;
707                    }
708    
709                    xml = _sanitizeXML(xml);
710    
711                    String systemDefaultLanguageId = LocaleUtil.toLanguageId(
712                            LocaleUtil.getDefault());
713    
714                    XMLStreamReader xmlStreamReader = null;
715                    XMLStreamWriter xmlStreamWriter = null;
716    
717                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
718    
719                    ClassLoader contextClassLoader =
720                            ClassLoaderUtil.getContextClassLoader();
721    
722                    try {
723                            if (contextClassLoader != portalClassLoader) {
724                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
725                            }
726    
727                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
728    
729                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
730                                    new UnsyncStringReader(xml));
731    
732                            String availableLocales = StringPool.BLANK;
733                            String defaultLanguageId = StringPool.BLANK;
734    
735                            // Read root node
736    
737                            if (xmlStreamReader.hasNext()) {
738                                    xmlStreamReader.nextTag();
739    
740                                    availableLocales = xmlStreamReader.getAttributeValue(
741                                            null, _AVAILABLE_LOCALES);
742                                    defaultLanguageId = xmlStreamReader.getAttributeValue(
743                                            null, _DEFAULT_LOCALE);
744    
745                                    if (Validator.isNull(defaultLanguageId)) {
746                                            defaultLanguageId = systemDefaultLanguageId;
747                                    }
748                            }
749    
750                            if ((availableLocales != null) &&
751                                    availableLocales.contains(requestedLanguageId)) {
752    
753                                    availableLocales = StringUtil.removeFromList(
754                                            availableLocales, requestedLanguageId);
755    
756                                    UnsyncStringWriter unsyncStringWriter =
757                                            new UnsyncStringWriter();
758    
759                                    XMLOutputFactory xmlOutputFactory =
760                                            XMLOutputFactory.newInstance();
761    
762                                    xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
763                                            unsyncStringWriter);
764    
765                                    xmlStreamWriter.writeStartDocument();
766                                    xmlStreamWriter.writeStartElement(_ROOT);
767    
768                                    if (localized) {
769                                            xmlStreamWriter.writeAttribute(
770                                                    _AVAILABLE_LOCALES, availableLocales);
771                                            xmlStreamWriter.writeAttribute(
772                                                    _DEFAULT_LOCALE, defaultLanguageId);
773                                    }
774    
775                                    _copyNonExempt(
776                                            xmlStreamReader, xmlStreamWriter, requestedLanguageId,
777                                            defaultLanguageId, cdata);
778    
779                                    xmlStreamWriter.writeEndElement();
780                                    xmlStreamWriter.writeEndDocument();
781    
782                                    xmlStreamWriter.close();
783                                    xmlStreamWriter = null;
784    
785                                    xml = unsyncStringWriter.toString();
786                            }
787                    }
788                    catch (Exception e) {
789                            if (_log.isWarnEnabled()) {
790                                    _log.warn(e, e);
791                            }
792                    }
793                    finally {
794                            if (contextClassLoader != portalClassLoader) {
795                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
796                            }
797    
798                            if (xmlStreamReader != null) {
799                                    try {
800                                            xmlStreamReader.close();
801                                    }
802                                    catch (Exception e) {
803                                    }
804                            }
805    
806                            if (xmlStreamWriter != null) {
807                                    try {
808                                            xmlStreamWriter.close();
809                                    }
810                                    catch (Exception e) {
811                                    }
812                            }
813                    }
814    
815                    return xml;
816            }
817    
818            @Override
819            public void setLocalizedPreferencesValues(
820                            PortletRequest portletRequest, PortletPreferences preferences,
821                            String parameter)
822                    throws Exception {
823    
824                    Map<Locale, String> map = getLocalizationMap(portletRequest, parameter);
825    
826                    for (Map.Entry<Locale, String> entry : map.entrySet()) {
827                            String languageId = LocaleUtil.toLanguageId(entry.getKey());
828                            String value = entry.getValue();
829    
830                            setPreferencesValue(preferences, parameter, languageId, value);
831                    }
832            }
833    
834            @Override
835            public void setPreferencesValue(
836                            PortletPreferences preferences, String key, String languageId,
837                            String value)
838                    throws Exception {
839    
840                    preferences.setValue(getPreferencesKey(key, languageId), value);
841            }
842    
843            @Override
844            public void setPreferencesValues(
845                            PortletPreferences preferences, String key, String languageId,
846                            String[] values)
847                    throws Exception {
848    
849                    preferences.setValues(getPreferencesKey(key, languageId), values);
850            }
851    
852            @Override
853            public String updateLocalization(
854                    Map<Locale, String> localizationMap, String xml, String key,
855                    String defaultLanguageId) {
856    
857                    Locale[] locales = LanguageUtil.getAvailableLocales();
858    
859                    for (Locale locale : locales) {
860                            String value = localizationMap.get(locale);
861    
862                            String languageId = LocaleUtil.toLanguageId(locale);
863    
864                            if (Validator.isNotNull(value)) {
865                                    xml = updateLocalization(
866                                            xml, key, value, languageId, defaultLanguageId);
867                            }
868                            else {
869                                    xml = removeLocalization(xml, key, languageId);
870                            }
871                    }
872    
873                    return xml;
874            }
875    
876            @Override
877            public String updateLocalization(String xml, String key, String value) {
878                    String defaultLanguageId = LocaleUtil.toLanguageId(
879                            LocaleUtil.getDefault());
880    
881                    return updateLocalization(
882                            xml, key, value, defaultLanguageId, defaultLanguageId);
883            }
884    
885            @Override
886            public String updateLocalization(
887                    String xml, String key, String value, String requestedLanguageId) {
888    
889                    String defaultLanguageId = LocaleUtil.toLanguageId(
890                            LocaleUtil.getDefault());
891    
892                    return updateLocalization(
893                            xml, key, value, requestedLanguageId, defaultLanguageId);
894            }
895    
896            @Override
897            public String updateLocalization(
898                    String xml, String key, String value, String requestedLanguageId,
899                    String defaultLanguageId) {
900    
901                    return updateLocalization(
902                            xml, key, value, requestedLanguageId, defaultLanguageId, false);
903            }
904    
905            @Override
906            public String updateLocalization(
907                    String xml, String key, String value, String requestedLanguageId,
908                    String defaultLanguageId, boolean cdata) {
909    
910                    return updateLocalization(
911                            xml, key, value, requestedLanguageId, defaultLanguageId, cdata,
912                            true);
913            }
914    
915            @Override
916            public String updateLocalization(
917                    String xml, String key, String value, String requestedLanguageId,
918                    String defaultLanguageId, boolean cdata, boolean localized) {
919    
920                    xml = _sanitizeXML(xml);
921    
922                    XMLStreamReader xmlStreamReader = null;
923                    XMLStreamWriter xmlStreamWriter = null;
924    
925                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
926    
927                    ClassLoader contextClassLoader =
928                            ClassLoaderUtil.getContextClassLoader();
929    
930                    try {
931                            if (contextClassLoader != portalClassLoader) {
932                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
933                            }
934    
935                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
936    
937                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
938                                    new UnsyncStringReader(xml));
939    
940                            String availableLocales = StringPool.BLANK;
941    
942                            // Read root node
943    
944                            if (xmlStreamReader.hasNext()) {
945                                    xmlStreamReader.nextTag();
946    
947                                    availableLocales = xmlStreamReader.getAttributeValue(
948                                            null, _AVAILABLE_LOCALES);
949    
950                                    if (Validator.isNull(availableLocales)) {
951                                            availableLocales = defaultLanguageId;
952                                    }
953    
954                                    if (!availableLocales.contains(requestedLanguageId)) {
955                                            availableLocales = StringUtil.add(
956                                                    availableLocales, requestedLanguageId,
957                                                    StringPool.COMMA);
958                                    }
959                            }
960    
961                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
962    
963                            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
964    
965                            xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
966                                    unsyncStringWriter);
967    
968                            xmlStreamWriter.writeStartDocument();
969                            xmlStreamWriter.writeStartElement(_ROOT);
970    
971                            if (localized) {
972                                    xmlStreamWriter.writeAttribute(
973                                            _AVAILABLE_LOCALES, availableLocales);
974                                    xmlStreamWriter.writeAttribute(
975                                            _DEFAULT_LOCALE, defaultLanguageId);
976                            }
977    
978                            _copyNonExempt(
979                                    xmlStreamReader, xmlStreamWriter, requestedLanguageId,
980                                    defaultLanguageId, cdata);
981    
982                            xmlStreamWriter.writeStartElement(key);
983    
984                            if (localized) {
985                                    xmlStreamWriter.writeAttribute(
986                                            _LANGUAGE_ID, requestedLanguageId);
987                            }
988    
989                            if (cdata) {
990                                    xmlStreamWriter.writeCData(value);
991                            }
992                            else {
993                                    xmlStreamWriter.writeCharacters(value);
994                            }
995    
996                            xmlStreamWriter.writeEndElement();
997                            xmlStreamWriter.writeEndElement();
998                            xmlStreamWriter.writeEndDocument();
999    
1000                            xmlStreamWriter.close();
1001                            xmlStreamWriter = null;
1002    
1003                            xml = unsyncStringWriter.toString();
1004                    }
1005                    catch (Exception e) {
1006                            if (_log.isWarnEnabled()) {
1007                                    _log.warn(e, e);
1008                            }
1009                    }
1010                    finally {
1011                            if (contextClassLoader != portalClassLoader) {
1012                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
1013                            }
1014    
1015                            if (xmlStreamReader != null) {
1016                                    try {
1017                                            xmlStreamReader.close();
1018                                    }
1019                                    catch (Exception e) {
1020                                    }
1021                            }
1022    
1023                            if (xmlStreamWriter != null) {
1024                                    try {
1025                                            xmlStreamWriter.close();
1026                                    }
1027                                    catch (Exception e) {
1028                                    }
1029                            }
1030                    }
1031    
1032                    return xml;
1033            }
1034    
1035            private void _copyNonExempt(
1036                            XMLStreamReader xmlStreamReader, XMLStreamWriter xmlStreamWriter,
1037                            String exemptLanguageId, String defaultLanguageId, boolean cdata)
1038                    throws XMLStreamException {
1039    
1040                    while (xmlStreamReader.hasNext()) {
1041                            int event = xmlStreamReader.next();
1042    
1043                            if (event == XMLStreamConstants.START_ELEMENT) {
1044                                    String languageId = xmlStreamReader.getAttributeValue(
1045                                            null, _LANGUAGE_ID);
1046    
1047                                    if (Validator.isNull(languageId)) {
1048                                            languageId = defaultLanguageId;
1049                                    }
1050    
1051                                    if (!languageId.equals(exemptLanguageId)) {
1052                                            xmlStreamWriter.writeStartElement(
1053                                                    xmlStreamReader.getLocalName());
1054                                            xmlStreamWriter.writeAttribute(_LANGUAGE_ID, languageId);
1055    
1056                                            while (xmlStreamReader.hasNext()) {
1057                                                    event = xmlStreamReader.next();
1058    
1059                                                    if ((event == XMLStreamConstants.CHARACTERS) ||
1060                                                            (event == XMLStreamConstants.CDATA)) {
1061    
1062                                                            String text = xmlStreamReader.getText();
1063    
1064                                                            if (cdata) {
1065                                                                    xmlStreamWriter.writeCData(text);
1066                                                            }
1067                                                            else {
1068                                                                    xmlStreamWriter.writeCharacters(
1069                                                                            xmlStreamReader.getText());
1070                                                            }
1071    
1072                                                            break;
1073                                                    }
1074                                                    else if (event == XMLStreamConstants.END_ELEMENT) {
1075                                                            break;
1076                                                    }
1077                                            }
1078    
1079                                            xmlStreamWriter.writeEndElement();
1080                                    }
1081                            }
1082                            else if (event == XMLStreamConstants.END_DOCUMENT) {
1083                                    break;
1084                            }
1085                    }
1086            }
1087    
1088            private String _getCachedValue(
1089                    String xml, String requestedLanguageId, boolean useDefault) {
1090    
1091                    String value = null;
1092    
1093                    Map<Tuple, String> valueMap = _cache.get(xml);
1094    
1095                    if (valueMap != null) {
1096                            Tuple subkey = new Tuple(useDefault, requestedLanguageId);
1097    
1098                            value = valueMap.get(subkey);
1099                    }
1100    
1101                    return value;
1102            }
1103    
1104            private String _getLocalization(
1105                    String bundleName, Locale locale, ClassLoader classLoader, String key,
1106                    String defaultValue) {
1107    
1108                    ResourceBundle resourceBundle = ResourceBundle.getBundle(
1109                            bundleName, locale, classLoader);
1110    
1111                    String value = null;
1112    
1113                    if (resourceBundle.containsKey(key)) {
1114                            try {
1115                                    value = resourceBundle.getString(key);
1116    
1117                                    value = new String(
1118                                            value.getBytes(StringPool.ISO_8859_1), StringPool.UTF8);
1119                            }
1120    
1121                            catch (Exception e) {
1122                            }
1123                    }
1124    
1125                    if (Validator.isNotNull(value)) {
1126                            value = LanguageResources.fixValue(value);
1127                    }
1128                    else {
1129                            value = LanguageUtil.get(locale, key, defaultValue);
1130                    }
1131    
1132                    return value;
1133            }
1134    
1135            private String _getRootAttributeValue(
1136                    Document document, String name, String defaultValue) {
1137    
1138                    Element rootElement = document.getRootElement();
1139    
1140                    return rootElement.attributeValue(name, defaultValue);
1141            }
1142    
1143            private String _getRootAttributeValue(
1144                    String xml, String name, String defaultValue) {
1145    
1146                    String value = null;
1147    
1148                    XMLStreamReader xmlStreamReader = null;
1149    
1150                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
1151    
1152                    ClassLoader contextClassLoader =
1153                            ClassLoaderUtil.getContextClassLoader();
1154    
1155                    try {
1156                            if (contextClassLoader != portalClassLoader) {
1157                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
1158                            }
1159    
1160                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
1161    
1162                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
1163                                    new UnsyncStringReader(xml));
1164    
1165                            if (xmlStreamReader.hasNext()) {
1166                                    xmlStreamReader.nextTag();
1167    
1168                                    value = xmlStreamReader.getAttributeValue(null, name);
1169                            }
1170                    }
1171                    catch (Exception e) {
1172                            if (_log.isWarnEnabled()) {
1173                                    _log.warn(e, e);
1174                            }
1175                    }
1176                    finally {
1177                            if (contextClassLoader != portalClassLoader) {
1178                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
1179                            }
1180    
1181                            if (xmlStreamReader != null) {
1182                                    try {
1183                                            xmlStreamReader.close();
1184                                    }
1185                                    catch (Exception e) {
1186                                    }
1187                            }
1188                    }
1189    
1190                    if (Validator.isNull(value)) {
1191                            value = defaultValue;
1192                    }
1193    
1194                    return value;
1195            }
1196    
1197            private String _sanitizeXML(String xml) {
1198                    if (Validator.isNull(xml) || !xml.contains("<root")) {
1199                            xml = _EMPTY_ROOT_NODE;
1200                    }
1201    
1202                    return xml;
1203            }
1204    
1205            private void _setCachedValue(
1206                    String xml, String requestedLanguageId, boolean useDefault,
1207                    String value) {
1208    
1209                    if (Validator.isNotNull(xml) && !xml.equals(_EMPTY_ROOT_NODE)) {
1210                            synchronized (_cache) {
1211                                    Map<Tuple, String> map = _cache.get(xml);
1212    
1213                                    if (map == null) {
1214                                            map = new HashMap<Tuple, String>();
1215                                    }
1216    
1217                                    Tuple subkey = new Tuple(useDefault, requestedLanguageId);
1218    
1219                                    map.put(subkey, value);
1220    
1221                                    _cache.put(xml, map);
1222                            }
1223                    }
1224            }
1225    
1226            private static final String _AVAILABLE_LOCALES = "available-locales";
1227    
1228            private static final String _DEFAULT_LOCALE = "default-locale";
1229    
1230            private static final String _EMPTY_ROOT_NODE = "<root />";
1231    
1232            private static final String _LANGUAGE_ID = "language-id";
1233    
1234            private static final String _ROOT = "root";
1235    
1236            private static Log _log = LogFactoryUtil.getLog(LocalizationImpl.class);
1237    
1238            private Map<String, Map<Tuple, String>> _cache = new ReferenceMap(
1239                    ReferenceMap.SOFT, ReferenceMap.HARD);
1240    
1241    }