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