001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.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.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.LocaleUtil;
025    import com.liferay.portal.kernel.util.Localization;
026    import com.liferay.portal.kernel.util.ParamUtil;
027    import com.liferay.portal.kernel.util.PrefsParamUtil;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.Tuple;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.language.LanguageResources;
034    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
035    
036    import java.util.HashMap;
037    import java.util.Locale;
038    import java.util.Map;
039    import java.util.ResourceBundle;
040    
041    import javax.portlet.PortletPreferences;
042    import javax.portlet.PortletRequest;
043    
044    import javax.xml.stream.XMLInputFactory;
045    import javax.xml.stream.XMLOutputFactory;
046    import javax.xml.stream.XMLStreamConstants;
047    import javax.xml.stream.XMLStreamException;
048    import javax.xml.stream.XMLStreamReader;
049    import javax.xml.stream.XMLStreamWriter;
050    
051    import org.apache.commons.collections.map.ReferenceMap;
052    
053    /**
054     * @author Alexander Chow
055     * @author Jorge Ferrer
056     * @author Mauro Mariuzzo
057     * @author Julio Camarero
058     * @author Brian Wing Shun Chan
059     * @author Connor McKay
060     */
061    public class LocalizationImpl implements Localization {
062    
063            public Object deserialize(JSONObject jsonObject) {
064                    Locale[] locales = LanguageUtil.getAvailableLocales();
065    
066                    Map<Locale, String> map = new HashMap<Locale, String>();
067    
068                    for (Locale locale : locales) {
069                            String languageId = LocaleUtil.toLanguageId(locale);
070    
071                            String value = jsonObject.getString(languageId);
072    
073                            if (Validator.isNotNull(value)) {
074                                    map.put(locale, value);
075                            }
076                    }
077    
078                    return map;
079            }
080    
081            public String[] getAvailableLocales(String xml) {
082                    String attributeValue = _getRootAttribute(
083                            xml, _AVAILABLE_LOCALES, StringPool.BLANK);
084    
085                    return StringUtil.split(attributeValue);
086            }
087    
088            public Locale getDefaultImportLocale(
089                    String className, long classPK, Locale contentDefaultLocale,
090                    Locale[] contentAvailableLocales) {
091    
092                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
093    
094                    if (ArrayUtil.contains(availableLocales, contentDefaultLocale)) {
095                            return contentDefaultLocale;
096                    }
097    
098                    Locale defaultLocale = LocaleUtil.getDefault();
099    
100                    if (ArrayUtil.contains(contentAvailableLocales, defaultLocale)) {
101                            return defaultLocale;
102                    }
103    
104                    for (Locale contentAvailableLocale : contentAvailableLocales) {
105                            if (ArrayUtil.contains(availableLocales, contentAvailableLocale)) {
106                                    return contentAvailableLocale;
107                            }
108                    }
109    
110                    if (_log.isWarnEnabled()) {
111                            StringBundler sb = new StringBundler(9);
112    
113                            sb.append("Language ");
114                            sb.append(LocaleUtil.toLanguageId(contentDefaultLocale));
115                            sb.append(" is missing for ");
116                            sb.append(className);
117                            sb.append(" with primary key ");
118                            sb.append(classPK);
119                            sb.append(". Setting default language to ");
120                            sb.append(LocaleUtil.toLanguageId(defaultLocale));
121                            sb.append(".");
122    
123                            _log.warn(sb.toString());
124                    }
125    
126                    return defaultLocale;
127            }
128    
129            public String getDefaultLocale(String xml) {
130                    String defaultLanguageId = LocaleUtil.toLanguageId(
131                            LocaleUtil.getDefault());
132    
133                    return _getRootAttribute(xml, _DEFAULT_LOCALE, defaultLanguageId);
134            }
135    
136            public String getLocalization(String xml, String requestedLanguageId) {
137                    return getLocalization(xml, requestedLanguageId, true);
138            }
139    
140            public String getLocalization(
141                    String xml, String requestedLanguageId, boolean useDefault) {
142    
143                    String value = _getCachedValue(xml, requestedLanguageId, useDefault);
144    
145                    if (value != null) {
146                            return value;
147                    }
148                    else {
149                            value = StringPool.BLANK;
150                    }
151    
152                    String systemDefaultLanguageId = LocaleUtil.toLanguageId(
153                            LocaleUtil.getDefault());
154    
155                    String priorityLanguageId = null;
156    
157                    Locale requestedLocale = LocaleUtil.fromLanguageId(requestedLanguageId);
158    
159                    if (useDefault &&
160                            LanguageUtil.isDuplicateLanguageCode(
161                                    requestedLocale.getLanguage())) {
162    
163                            Locale priorityLocale = LanguageUtil.getLocale(
164                                    requestedLocale.getLanguage());
165    
166                            if (!requestedLanguageId.equals(priorityLanguageId)) {
167                                    priorityLanguageId = LocaleUtil.toLanguageId(priorityLocale);
168                            }
169                    }
170    
171                    if (!Validator.isXml(xml)) {
172                            if (useDefault ||
173                                    requestedLanguageId.equals(systemDefaultLanguageId)) {
174    
175                                    value = xml;
176                            }
177    
178                            _setCachedValue(xml, requestedLanguageId, useDefault, value);
179    
180                            return value;
181                    }
182    
183                    XMLStreamReader xmlStreamReader = null;
184    
185                    ClassLoader portalClassLoader =
186                            PACLClassLoaderUtil.getPortalClassLoader();
187    
188                    ClassLoader contextClassLoader =
189                            PACLClassLoaderUtil.getContextClassLoader();
190    
191                    try {
192                            if (contextClassLoader != portalClassLoader) {
193                                    PACLClassLoaderUtil.setContextClassLoader(portalClassLoader);
194                            }
195    
196                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
197    
198                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
199                                    new UnsyncStringReader(xml));
200    
201                            String defaultLanguageId = StringPool.BLANK;
202    
203                            // Skip root node
204    
205                            if (xmlStreamReader.hasNext()) {
206                                    xmlStreamReader.nextTag();
207    
208                                    defaultLanguageId = xmlStreamReader.getAttributeValue(
209                                            null, _DEFAULT_LOCALE);
210    
211                                    if (Validator.isNull(defaultLanguageId)) {
212                                            defaultLanguageId = systemDefaultLanguageId;
213                                    }
214                            }
215    
216                            // Find specified language and/or default language
217    
218                            String defaultValue = StringPool.BLANK;
219                            String priorityValue = StringPool.BLANK;
220    
221                            while (xmlStreamReader.hasNext()) {
222                                    int event = xmlStreamReader.next();
223    
224                                    if (event == XMLStreamConstants.START_ELEMENT) {
225                                            String languageId = xmlStreamReader.getAttributeValue(
226                                                    null, _LANGUAGE_ID);
227    
228                                            if (Validator.isNull(languageId)) {
229                                                    languageId = defaultLanguageId;
230                                            }
231    
232                                            if (languageId.equals(defaultLanguageId) ||
233                                                    languageId.equals(priorityLanguageId) ||
234                                                    languageId.equals(requestedLanguageId)) {
235    
236                                                    String text = xmlStreamReader.getElementText();
237    
238                                                    if (languageId.equals(defaultLanguageId)) {
239                                                            defaultValue = text;
240                                                    }
241    
242                                                    if (languageId.equals(priorityLanguageId)) {
243                                                            priorityValue = text;
244                                                    }
245    
246                                                    if (languageId.equals(requestedLanguageId)) {
247                                                            value = text;
248                                                    }
249    
250                                                    if (Validator.isNotNull(value)) {
251                                                            break;
252                                                    }
253                                            }
254                                    }
255                                    else if (event == XMLStreamConstants.END_DOCUMENT) {
256                                            break;
257                                    }
258                            }
259    
260                            if (useDefault && Validator.isNotNull(priorityLanguageId) &&
261                                    Validator.isNull(value) && Validator.isNotNull(priorityValue)) {
262    
263                                    value = priorityValue;
264                            }
265    
266                            if (useDefault && Validator.isNull(value)) {
267                                    value = defaultValue;
268                            }
269                    }
270                    catch (Exception e) {
271                            if (_log.isWarnEnabled()) {
272                                    _log.warn(e, e);
273                            }
274                    }
275                    finally {
276                            if (contextClassLoader != portalClassLoader) {
277                                    PACLClassLoaderUtil.setContextClassLoader(contextClassLoader);
278                            }
279    
280                            if (xmlStreamReader != null) {
281                                    try {
282                                            xmlStreamReader.close();
283                                    }
284                                    catch (Exception e) {
285                                    }
286                            }
287                    }
288    
289                    _setCachedValue(xml, requestedLanguageId, useDefault, value);
290    
291                    return value;
292            }
293    
294            public Map<Locale, String> getLocalizationMap(
295                    PortletPreferences preferences, String parameter) {
296    
297                    Locale[] locales = LanguageUtil.getAvailableLocales();
298    
299                    Map<Locale, String> map = new HashMap<Locale, String>();
300    
301                    for (Locale locale : locales) {
302                            String languageId = LocaleUtil.toLanguageId(locale);
303    
304                            String localeParameter = parameter.concat(
305                                    StringPool.UNDERLINE).concat(languageId);
306    
307                            map.put(
308                                    locale,
309                                    preferences.getValue(localeParameter, StringPool.BLANK));
310                    }
311    
312                    return map;
313            }
314    
315            public Map<Locale, String> getLocalizationMap(
316                    PortletRequest portletRequest, String parameter) {
317    
318                    Locale[] locales = LanguageUtil.getAvailableLocales();
319    
320                    Map<Locale, String> map = new HashMap<Locale, String>();
321    
322                    for (Locale locale : locales) {
323                            String languageId = LocaleUtil.toLanguageId(locale);
324    
325                            String localeParameter = parameter.concat(
326                                    StringPool.UNDERLINE).concat(languageId);
327    
328                            map.put(
329                                    locale, ParamUtil.getString(portletRequest, localeParameter));
330                    }
331    
332                    return map;
333            }
334    
335            public Map<Locale, String> getLocalizationMap(String xml) {
336                    Locale[] locales = LanguageUtil.getAvailableLocales();
337    
338                    Map<Locale, String> map = new HashMap<Locale, String>();
339    
340                    for (Locale locale : locales) {
341                            String languageId = LocaleUtil.toLanguageId(locale);
342    
343                            map.put(locale, getLocalization(xml, languageId, false));
344                    }
345    
346                    return map;
347            }
348    
349            public Map<Locale, String> getLocalizationMap(
350                    String bundleName, ClassLoader classLoader, String key,
351                    boolean includeBetaLocales) {
352    
353                    if (key == null) {
354                            return null;
355                    }
356    
357                    Map<Locale, String> map = new HashMap<Locale, String>();
358    
359                    Locale defaultLocale = LocaleUtil.getDefault();
360    
361                    String defaultValue = _getLocalization(
362                            bundleName, defaultLocale, classLoader, key, key);
363    
364                    map.put(defaultLocale, defaultValue);
365    
366                    Locale[] locales = null;
367    
368                    if (includeBetaLocales) {
369                            locales = LanguageUtil.getAvailableLocales();
370                    }
371                    else {
372                            locales = LanguageUtil.getSupportedLocales();
373                    }
374    
375                    for (Locale locale : locales) {
376                            if (locale.equals(defaultLocale)) {
377                                    continue;
378                            }
379    
380                            String value = _getLocalization(
381                                    bundleName, locale, classLoader, key, null);
382    
383                            if (Validator.isNotNull(value) && !value.equals(defaultValue)) {
384                                    map.put(locale, value);
385                            }
386                    }
387    
388                    return map;
389            }
390    
391            public Map<Locale, String> getLocalizationMap(
392                    String[] languageIds, String[] values) {
393    
394                    Map<Locale, String> map = new HashMap<Locale, String>();
395    
396                    for (int i = 0; i < values.length; i++) {
397                            Locale locale = LocaleUtil.fromLanguageId(languageIds[i]);
398    
399                            map.put(locale, values[i]);
400                    }
401    
402                    return map;
403            }
404    
405            public String getLocalizationXmlFromPreferences(
406                    PortletPreferences preferences, PortletRequest portletRequest,
407                    String parameter) {
408    
409                    String xml = StringPool.BLANK;
410    
411                    Locale[] locales = LanguageUtil.getAvailableLocales();
412                    Locale defaultLocale = LocaleUtil.getDefault();
413                    String defaultLanguageId = LocaleUtil.toLanguageId(defaultLocale);
414    
415                    for (Locale locale : locales) {
416                            String languageId = LocaleUtil.toLanguageId(locale);
417    
418                            String localParameter =
419                                    parameter + StringPool.UNDERLINE + languageId;
420    
421                            String value = PrefsParamUtil.getString(
422                                    preferences, portletRequest, localParameter);
423    
424                            if (Validator.isNotNull(value)) {
425                                    xml = updateLocalization(xml, parameter, value, languageId);
426                            }
427                    }
428    
429                    if (Validator.isNull(getLocalization(xml, defaultLanguageId))) {
430                            String oldValue = PrefsParamUtil.getString(
431                                    preferences, portletRequest, parameter);
432    
433                            if (Validator.isNotNull(oldValue)) {
434                                    xml = updateLocalization(xml, parameter, oldValue);
435                            }
436                    }
437    
438                    return xml;
439            }
440    
441            public Map<Locale, String> getLocalizedParameter(
442                    PortletRequest portletRequest, String parameter) {
443    
444                    return getLocalizationMap(portletRequest, parameter);
445            }
446    
447            public String getPreferencesKey(String key, String languageId) {
448                    String defaultLanguageId = LocaleUtil.toLanguageId(
449                            LocaleUtil.getDefault());
450    
451                    if (!languageId.equals(defaultLanguageId)) {
452                            key += StringPool.UNDERLINE + languageId;
453                    }
454    
455                    return key;
456            }
457    
458            public String getPreferencesValue(
459                    PortletPreferences preferences, String key, String languageId) {
460    
461                    return getPreferencesValue(preferences, key, languageId, true);
462            }
463    
464            public String getPreferencesValue(
465                    PortletPreferences preferences, String key, String languageId,
466                    boolean useDefault) {
467    
468                    String localizedKey = getPreferencesKey(key, languageId);
469    
470                    String value = preferences.getValue(localizedKey, StringPool.BLANK);
471    
472                    if (useDefault && Validator.isNull(value)) {
473                            value = preferences.getValue(key, StringPool.BLANK);
474                    }
475    
476                    return value;
477            }
478    
479            public String[] getPreferencesValues(
480                    PortletPreferences preferences, String key, String languageId) {
481    
482                    return getPreferencesValues(preferences, key, languageId, true);
483            }
484    
485            public String[] getPreferencesValues(
486                    PortletPreferences preferences, String key, String languageId,
487                    boolean useDefault) {
488    
489                    String localizedKey = getPreferencesKey(key, languageId);
490    
491                    String[] values = preferences.getValues(localizedKey, new String[0]);
492    
493                    if (useDefault && Validator.isNull(values)) {
494                            values = preferences.getValues(key, new String[0]);
495                    }
496    
497                    return values;
498            }
499    
500            public String removeLocalization(
501                    String xml, String key, String requestedLanguageId) {
502    
503                    return removeLocalization(xml, key, requestedLanguageId, false);
504            }
505    
506            public String removeLocalization(
507                    String xml, String key, String requestedLanguageId, boolean cdata) {
508    
509                    return removeLocalization(xml, key, requestedLanguageId, cdata, true);
510            }
511    
512            public String removeLocalization(
513                    String xml, String key, String requestedLanguageId, boolean cdata,
514                    boolean localized) {
515    
516                    if (Validator.isNull(xml)) {
517                            return StringPool.BLANK;
518                    }
519    
520                    xml = _sanitizeXML(xml);
521    
522                    String systemDefaultLanguageId = LocaleUtil.toLanguageId(
523                            LocaleUtil.getDefault());
524    
525                    XMLStreamReader xmlStreamReader = null;
526                    XMLStreamWriter xmlStreamWriter = null;
527    
528                    ClassLoader portalClassLoader =
529                            PACLClassLoaderUtil.getPortalClassLoader();
530    
531                    ClassLoader contextClassLoader =
532                            PACLClassLoaderUtil.getContextClassLoader();
533    
534                    try {
535                            if (contextClassLoader != portalClassLoader) {
536                                    PACLClassLoaderUtil.setContextClassLoader(portalClassLoader);
537                            }
538    
539                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
540    
541                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
542                                    new UnsyncStringReader(xml));
543    
544                            String availableLocales = StringPool.BLANK;
545                            String defaultLanguageId = StringPool.BLANK;
546    
547                            // Read root node
548    
549                            if (xmlStreamReader.hasNext()) {
550                                    xmlStreamReader.nextTag();
551    
552                                    availableLocales = xmlStreamReader.getAttributeValue(
553                                            null, _AVAILABLE_LOCALES);
554                                    defaultLanguageId = xmlStreamReader.getAttributeValue(
555                                            null, _DEFAULT_LOCALE);
556    
557                                    if (Validator.isNull(defaultLanguageId)) {
558                                            defaultLanguageId = systemDefaultLanguageId;
559                                    }
560                            }
561    
562                            if ((availableLocales != null) &&
563                                    availableLocales.contains(requestedLanguageId)) {
564    
565                                    availableLocales = StringUtil.remove(
566                                            availableLocales, requestedLanguageId, StringPool.COMMA);
567    
568                                    UnsyncStringWriter unsyncStringWriter =
569                                            new UnsyncStringWriter();
570    
571                                    XMLOutputFactory xmlOutputFactory =
572                                            XMLOutputFactory.newInstance();
573    
574                                    xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
575                                            unsyncStringWriter);
576    
577                                    xmlStreamWriter.writeStartDocument();
578                                    xmlStreamWriter.writeStartElement(_ROOT);
579    
580                                    if (localized) {
581                                            xmlStreamWriter.writeAttribute(
582                                                    _AVAILABLE_LOCALES, availableLocales);
583                                            xmlStreamWriter.writeAttribute(
584                                                    _DEFAULT_LOCALE, defaultLanguageId);
585                                    }
586    
587                                    _copyNonExempt(
588                                            xmlStreamReader, xmlStreamWriter, requestedLanguageId,
589                                            defaultLanguageId, cdata);
590    
591                                    xmlStreamWriter.writeEndElement();
592                                    xmlStreamWriter.writeEndDocument();
593    
594                                    xmlStreamWriter.close();
595                                    xmlStreamWriter = null;
596    
597                                    xml = unsyncStringWriter.toString();
598                            }
599                    }
600                    catch (Exception e) {
601                            if (_log.isWarnEnabled()) {
602                                    _log.warn(e, e);
603                            }
604                    }
605                    finally {
606                            if (contextClassLoader != portalClassLoader) {
607                                    PACLClassLoaderUtil.setContextClassLoader(contextClassLoader);
608                            }
609    
610                            if (xmlStreamReader != null) {
611                                    try {
612                                            xmlStreamReader.close();
613                                    }
614                                    catch (Exception e) {
615                                    }
616                            }
617    
618                            if (xmlStreamWriter != null) {
619                                    try {
620                                            xmlStreamWriter.close();
621                                    }
622                                    catch (Exception e) {
623                                    }
624                            }
625                    }
626    
627                    return xml;
628            }
629    
630            public void setLocalizedPreferencesValues(
631                            PortletRequest portletRequest, PortletPreferences preferences,
632                            String parameter)
633                    throws Exception {
634    
635                    Map<Locale, String> map = getLocalizationMap(portletRequest, parameter);
636    
637                    for (Map.Entry<Locale, String> entry : map.entrySet()) {
638                            String languageId = LocaleUtil.toLanguageId(entry.getKey());
639                            String value = entry.getValue();
640    
641                            setPreferencesValue(preferences, parameter, languageId, value);
642                    }
643            }
644    
645            public void setPreferencesValue(
646                            PortletPreferences preferences, String key, String languageId,
647                            String value)
648                    throws Exception {
649    
650                    preferences.setValue(getPreferencesKey(key, languageId), value);
651            }
652    
653            public void setPreferencesValues(
654                            PortletPreferences preferences, String key, String languageId,
655                            String[] values)
656                    throws Exception {
657    
658                    preferences.setValues(getPreferencesKey(key, languageId), values);
659            }
660    
661            public String updateLocalization(
662                    Map<Locale, String> localizationMap, String xml, String key,
663                    String defaultLanguageId) {
664    
665                    Locale[] locales = LanguageUtil.getAvailableLocales();
666    
667                    for (Locale locale : locales) {
668                            String value = localizationMap.get(locale);
669    
670                            String languageId = LocaleUtil.toLanguageId(locale);
671    
672                            if (Validator.isNotNull(value)) {
673                                    xml = updateLocalization(
674                                            xml, key, value, languageId, defaultLanguageId);
675                            }
676                            else {
677                                    xml = removeLocalization(xml, key, languageId);
678                            }
679                    }
680    
681                    return xml;
682            }
683    
684            public String updateLocalization(String xml, String key, String value) {
685                    String defaultLanguageId = LocaleUtil.toLanguageId(
686                            LocaleUtil.getDefault());
687    
688                    return updateLocalization(
689                            xml, key, value, defaultLanguageId, defaultLanguageId);
690            }
691    
692            public String updateLocalization(
693                    String xml, String key, String value, String requestedLanguageId) {
694    
695                    String defaultLanguageId = LocaleUtil.toLanguageId(
696                            LocaleUtil.getDefault());
697    
698                    return updateLocalization(
699                            xml, key, value, requestedLanguageId, defaultLanguageId);
700            }
701    
702            public String updateLocalization(
703                    String xml, String key, String value, String requestedLanguageId,
704                    String defaultLanguageId) {
705    
706                    return updateLocalization(
707                            xml, key, value, requestedLanguageId, defaultLanguageId, false);
708            }
709    
710            public String updateLocalization(
711                    String xml, String key, String value, String requestedLanguageId,
712                    String defaultLanguageId, boolean cdata) {
713    
714                    return updateLocalization(
715                            xml, key, value, requestedLanguageId, defaultLanguageId, cdata,
716                            true);
717            }
718    
719            public String updateLocalization(
720                    String xml, String key, String value, String requestedLanguageId,
721                    String defaultLanguageId, boolean cdata, boolean localized) {
722    
723                    xml = _sanitizeXML(xml);
724    
725                    XMLStreamReader xmlStreamReader = null;
726                    XMLStreamWriter xmlStreamWriter = null;
727    
728                    ClassLoader portalClassLoader =
729                            PACLClassLoaderUtil.getPortalClassLoader();
730    
731                    ClassLoader contextClassLoader =
732                            PACLClassLoaderUtil.getContextClassLoader();
733    
734                    try {
735                            if (contextClassLoader != portalClassLoader) {
736                                    PACLClassLoaderUtil.setContextClassLoader(portalClassLoader);
737                            }
738    
739                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
740    
741                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
742                                    new UnsyncStringReader(xml));
743    
744                            String availableLocales = StringPool.BLANK;
745    
746                            // Read root node
747    
748                            if (xmlStreamReader.hasNext()) {
749                                    xmlStreamReader.nextTag();
750    
751                                    availableLocales = xmlStreamReader.getAttributeValue(
752                                            null, _AVAILABLE_LOCALES);
753    
754                                    if (Validator.isNull(availableLocales)) {
755                                            availableLocales = defaultLanguageId;
756                                    }
757    
758                                    if (!availableLocales.contains(requestedLanguageId)) {
759                                            availableLocales = StringUtil.add(
760                                                    availableLocales, requestedLanguageId,
761                                                    StringPool.COMMA);
762                                    }
763                            }
764    
765                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
766    
767                            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
768    
769                            xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
770                                    unsyncStringWriter);
771    
772                            xmlStreamWriter.writeStartDocument();
773                            xmlStreamWriter.writeStartElement(_ROOT);
774    
775                            if (localized) {
776                                    xmlStreamWriter.writeAttribute(
777                                            _AVAILABLE_LOCALES, availableLocales);
778                                    xmlStreamWriter.writeAttribute(
779                                            _DEFAULT_LOCALE, defaultLanguageId);
780                            }
781    
782                            _copyNonExempt(
783                                    xmlStreamReader, xmlStreamWriter, requestedLanguageId,
784                                    defaultLanguageId, cdata);
785    
786                            xmlStreamWriter.writeStartElement(key);
787    
788                            if (localized) {
789                                    xmlStreamWriter.writeAttribute(
790                                            _LANGUAGE_ID, requestedLanguageId);
791                            }
792    
793                            if (cdata) {
794                                    xmlStreamWriter.writeCData(value);
795                            }
796                            else {
797                                    xmlStreamWriter.writeCharacters(value);
798                            }
799    
800                            xmlStreamWriter.writeEndElement();
801                            xmlStreamWriter.writeEndElement();
802                            xmlStreamWriter.writeEndDocument();
803    
804                            xmlStreamWriter.close();
805                            xmlStreamWriter = null;
806    
807                            xml = unsyncStringWriter.toString();
808                    }
809                    catch (Exception e) {
810                            if (_log.isWarnEnabled()) {
811                                    _log.warn(e, e);
812                            }
813                    }
814                    finally {
815                            if (contextClassLoader != portalClassLoader) {
816                                    PACLClassLoaderUtil.setContextClassLoader(contextClassLoader);
817                            }
818    
819                            if (xmlStreamReader != null) {
820                                    try {
821                                            xmlStreamReader.close();
822                                    }
823                                    catch (Exception e) {
824                                    }
825                            }
826    
827                            if (xmlStreamWriter != null) {
828                                    try {
829                                            xmlStreamWriter.close();
830                                    }
831                                    catch (Exception e) {
832                                    }
833                            }
834                    }
835    
836                    return xml;
837            }
838    
839            private void _copyNonExempt(
840                            XMLStreamReader xmlStreamReader, XMLStreamWriter xmlStreamWriter,
841                            String exemptLanguageId, String defaultLanguageId, boolean cdata)
842                    throws XMLStreamException {
843    
844                    while (xmlStreamReader.hasNext()) {
845                            int event = xmlStreamReader.next();
846    
847                            if (event == XMLStreamConstants.START_ELEMENT) {
848                                    String languageId = xmlStreamReader.getAttributeValue(
849                                            null, _LANGUAGE_ID);
850    
851                                    if (Validator.isNull(languageId)) {
852                                            languageId = defaultLanguageId;
853                                    }
854    
855                                    if (!languageId.equals(exemptLanguageId)) {
856                                            xmlStreamWriter.writeStartElement(
857                                                    xmlStreamReader.getLocalName());
858                                            xmlStreamWriter.writeAttribute(_LANGUAGE_ID, languageId);
859    
860                                            while (xmlStreamReader.hasNext()) {
861                                                    event = xmlStreamReader.next();
862    
863                                                    if ((event == XMLStreamConstants.CHARACTERS) ||
864                                                            (event == XMLStreamConstants.CDATA)) {
865    
866                                                            String text = xmlStreamReader.getText();
867    
868                                                            if (cdata) {
869                                                                    xmlStreamWriter.writeCData(text);
870                                                            }
871                                                            else {
872                                                                    xmlStreamWriter.writeCharacters(
873                                                                            xmlStreamReader.getText());
874                                                            }
875    
876                                                            break;
877                                                    }
878                                                    else if (event == XMLStreamConstants.END_ELEMENT) {
879                                                            break;
880                                                    }
881                                            }
882    
883                                            xmlStreamWriter.writeEndElement();
884                                    }
885                            }
886                            else if (event == XMLStreamConstants.END_DOCUMENT) {
887                                    break;
888                            }
889                    }
890            }
891    
892            private String _getCachedValue(
893                    String xml, String requestedLanguageId, boolean useDefault) {
894    
895                    String value = null;
896    
897                    Map<Tuple, String> valueMap = _cache.get(xml);
898    
899                    if (valueMap != null) {
900                            Tuple subkey = new Tuple(useDefault, requestedLanguageId);
901    
902                            value = valueMap.get(subkey);
903                    }
904    
905                    return value;
906            }
907    
908            private String _getLocalization(
909                    String bundleName, Locale locale, ClassLoader classLoader, String key,
910                    String defaultValue) {
911    
912                    ResourceBundle resourceBundle = ResourceBundle.getBundle(
913                            bundleName, locale, classLoader);
914    
915                    String value = null;
916    
917                    try {
918                            value = resourceBundle.getString(key);
919    
920                            value = new String(
921                                    value.getBytes(StringPool.ISO_8859_1), StringPool.UTF8);
922                    }
923    
924                    catch (Exception e) {
925                    }
926    
927                    if (Validator.isNotNull(value)) {
928                            value = LanguageResources.fixValue(value);
929                    }
930                    else {
931                            value = LanguageUtil.get(locale, key, defaultValue);
932                    }
933    
934                    return value;
935            }
936    
937            private String _getRootAttribute(
938                    String xml, String name, String defaultValue) {
939    
940                    String value = null;
941    
942                    XMLStreamReader xmlStreamReader = null;
943    
944                    ClassLoader portalClassLoader =
945                            PACLClassLoaderUtil.getPortalClassLoader();
946    
947                    ClassLoader contextClassLoader =
948                            PACLClassLoaderUtil.getContextClassLoader();
949    
950                    try {
951                            if (contextClassLoader != portalClassLoader) {
952                                    PACLClassLoaderUtil.setContextClassLoader(portalClassLoader);
953                            }
954    
955                            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
956    
957                            xmlStreamReader = xmlInputFactory.createXMLStreamReader(
958                                    new UnsyncStringReader(xml));
959    
960                            if (xmlStreamReader.hasNext()) {
961                                    xmlStreamReader.nextTag();
962    
963                                    value = xmlStreamReader.getAttributeValue(null, name);
964                            }
965                    }
966                    catch (Exception e) {
967                            if (_log.isWarnEnabled()) {
968                                    _log.warn(e, e);
969                            }
970                    }
971                    finally {
972                            if (contextClassLoader != portalClassLoader) {
973                                    PACLClassLoaderUtil.setContextClassLoader(contextClassLoader);
974                            }
975    
976                            if (xmlStreamReader != null) {
977                                    try {
978                                            xmlStreamReader.close();
979                                    }
980                                    catch (Exception e) {
981                                    }
982                            }
983                    }
984    
985                    if (Validator.isNull(value)) {
986                            value = defaultValue;
987                    }
988    
989                    return value;
990            }
991    
992            private String _sanitizeXML(String xml) {
993                    if (Validator.isNull(xml) || !xml.contains("<root")) {
994                            xml = _EMPTY_ROOT_NODE;
995                    }
996    
997                    return xml;
998            }
999    
1000            private void _setCachedValue(
1001                    String xml, String requestedLanguageId, boolean useDefault,
1002                    String value) {
1003    
1004                    if (Validator.isNotNull(xml) && !xml.equals(_EMPTY_ROOT_NODE)) {
1005                            synchronized (_cache) {
1006                                    Map<Tuple, String> map = _cache.get(xml);
1007    
1008                                    if (map == null) {
1009                                            map = new HashMap<Tuple, String>();
1010                                    }
1011    
1012                                    Tuple subkey = new Tuple(useDefault, requestedLanguageId);
1013    
1014                                    map.put(subkey, value);
1015    
1016                                    _cache.put(xml, map);
1017                            }
1018                    }
1019            }
1020    
1021            private static final String _AVAILABLE_LOCALES = "available-locales";
1022    
1023            private static final String _DEFAULT_LOCALE = "default-locale";
1024    
1025            private static final String _EMPTY_ROOT_NODE = "<root />";
1026    
1027            private static final String _LANGUAGE_ID = "language-id";
1028    
1029            private static final String _ROOT = "root";
1030    
1031            private static Log _log = LogFactoryUtil.getLog(LocalizationImpl.class);
1032    
1033            private Map<String, Map<Tuple, String>> _cache = new ReferenceMap(
1034                    ReferenceMap.SOFT, ReferenceMap.HARD);
1035    
1036    }