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