1
14
15 package com.liferay.util;
16
17 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
18 import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
19 import com.liferay.portal.kernel.json.JSONObject;
20 import com.liferay.portal.kernel.language.LanguageUtil;
21 import com.liferay.portal.kernel.log.Log;
22 import com.liferay.portal.kernel.log.LogFactoryUtil;
23 import com.liferay.portal.kernel.util.LocaleUtil;
24 import com.liferay.portal.kernel.util.ParamUtil;
25 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
26 import com.liferay.portal.kernel.util.StringPool;
27 import com.liferay.portal.kernel.util.StringUtil;
28 import com.liferay.portal.kernel.util.Tuple;
29 import com.liferay.portal.kernel.util.Validator;
30
31 import java.util.HashMap;
32 import java.util.Locale;
33 import java.util.Map;
34
35 import javax.portlet.ActionRequest;
36 import javax.portlet.PortletPreferences;
37 import javax.portlet.PortletRequest;
38
39 import javax.xml.stream.XMLInputFactory;
40 import javax.xml.stream.XMLOutputFactory;
41 import javax.xml.stream.XMLStreamConstants;
42 import javax.xml.stream.XMLStreamException;
43 import javax.xml.stream.XMLStreamReader;
44 import javax.xml.stream.XMLStreamWriter;
45
46 import org.apache.commons.collections.map.ReferenceMap;
47
48
71 public class LocalizationUtil {
72
73 public static Object deserialize(JSONObject jsonObject) {
74 Locale[] locales = LanguageUtil.getAvailableLocales();
75
76 Map<Locale, String> map = new HashMap<Locale, String>();
77
78 for (Locale locale : locales) {
79 String languageId = LocaleUtil.toLanguageId(locale);
80
81 String value = jsonObject.getString(languageId);
82
83 if (Validator.isNotNull(value)) {
84 map.put(locale, value);
85 }
86 }
87
88 return map;
89 }
90
91 public static String[] getAvailableLocales(String xml) {
92 String attributeValue = _getRootAttribute(
93 xml, _AVAILABLE_LOCALES, StringPool.BLANK);
94
95 return StringUtil.split(attributeValue);
96 }
97
98 public static String getDefaultLocale(String xml) {
99 String defaultLanguageId = LocaleUtil.toLanguageId(
100 LocaleUtil.getDefault());
101
102 return _getRootAttribute(xml, _DEFAULT_LOCALE, defaultLanguageId);
103 }
104
105 public static String getLocalization(
106 String xml, String requestedLanguageId) {
107
108 return getLocalization(xml, requestedLanguageId, true);
109 }
110
111 public static String getLocalization(
112 String xml, String requestedLanguageId, boolean useDefault) {
113
114 String value = _getCachedValue(xml, requestedLanguageId, useDefault);
115
116 if (value != null) {
117 return value;
118 }
119 else {
120 value = StringPool.BLANK;
121 }
122
123 String systemDefaultLanguageId = LocaleUtil.toLanguageId(
124 LocaleUtil.getDefault());
125
126 String defaultValue = StringPool.BLANK;
127
128 if (!Validator.isXml(xml)) {
129 if (requestedLanguageId.equals(systemDefaultLanguageId)) {
130 value = xml;
131 }
132 else {
133 value = defaultValue;
134 }
135
136 _setCachedValue(xml, requestedLanguageId, useDefault, value);
137
138 return value;
139 }
140
141 XMLStreamReader xmlStreamReader = null;
142
143 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
144
145 Thread currentThread = Thread.currentThread();
146
147 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
148
149 try {
150 if (contextClassLoader != portalClassLoader) {
151 currentThread.setContextClassLoader(portalClassLoader);
152 }
153
154 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
155
156 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
157 new UnsyncStringReader(xml));
158
159 String defaultLanguageId = StringPool.BLANK;
160
161
163 if (xmlStreamReader.hasNext()) {
164 xmlStreamReader.nextTag();
165
166 defaultLanguageId = xmlStreamReader.getAttributeValue(
167 null, _DEFAULT_LOCALE);
168
169 if (Validator.isNull(defaultLanguageId)) {
170 defaultLanguageId = systemDefaultLanguageId;
171 }
172 }
173
174
176 while (xmlStreamReader.hasNext()) {
177 int event = xmlStreamReader.next();
178
179 if (event == XMLStreamConstants.START_ELEMENT) {
180 String languageId = xmlStreamReader.getAttributeValue(
181 null, _LANGUAGE_ID);
182
183 if (Validator.isNull(languageId)) {
184 languageId = defaultLanguageId;
185 }
186
187 if (languageId.equals(defaultLanguageId) ||
188 languageId.equals(requestedLanguageId)) {
189
190 while (xmlStreamReader.hasNext()) {
191 event = xmlStreamReader.next();
192
193 if (event == XMLStreamConstants.CHARACTERS ||
194 event == XMLStreamConstants.CDATA) {
195
196 String text = xmlStreamReader.getText();
197
198 if (languageId.equals(defaultLanguageId)) {
199 defaultValue = text;
200 }
201
202 if (languageId.equals(requestedLanguageId)) {
203 value = text;
204 }
205
206 break;
207 }
208 else if (event == XMLStreamConstants.END_ELEMENT) {
209 break;
210 }
211 }
212
213 if (Validator.isNotNull(value)) {
214 break;
215 }
216 }
217 }
218 else if (event == XMLStreamConstants.END_DOCUMENT) {
219 break;
220 }
221 }
222
223 if (useDefault && Validator.isNull(value)) {
224 value = defaultValue;
225 }
226 }
227 catch (Exception e) {
228 if (_log.isWarnEnabled()) {
229 _log.warn(e, e);
230 }
231 }
232 finally {
233 if (contextClassLoader != portalClassLoader) {
234 currentThread.setContextClassLoader(contextClassLoader);
235 }
236
237 if (xmlStreamReader != null) {
238 try {
239 xmlStreamReader.close();
240 }
241 catch (Exception e) {
242 }
243 }
244 }
245
246 _setCachedValue(xml, requestedLanguageId, useDefault, value);
247
248 return value;
249 }
250
251 public static Map<Locale, String> getLocalizationMap(
252 PortletRequest portletRequest, String parameter) {
253
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 String localeParameter =
262 parameter + StringPool.UNDERLINE + languageId;
263
264 map.put(
265 locale, ParamUtil.getString(portletRequest, localeParameter));
266 }
267
268 return map;
269 }
270
271 public static Map<Locale, String> getLocalizationMap(String xml) {
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 map.put(locale, getLocalization(xml, languageId));
280 }
281
282 return map;
283 }
284
285
288 public static Map<Locale, String> getLocalizedParameter(
289 PortletRequest portletRequest, String parameter) {
290
291 return getLocalizationMap(portletRequest, parameter);
292 }
293
294 public static String getPreferencesValue(
295 PortletPreferences preferences, String key, String languageId) {
296
297 return getPreferencesValue(preferences, key, languageId, true);
298 }
299
300 public static String getPreferencesValue(
301 PortletPreferences preferences, String key, String languageId,
302 boolean useDefault) {
303
304 String localizedKey = _getPreferencesKey(key, languageId);
305
306 String value = preferences.getValue(localizedKey, StringPool.BLANK);
307
308 if (useDefault && Validator.isNull(value)) {
309 value = preferences.getValue(key, StringPool.BLANK);
310 }
311
312 return value;
313 }
314
315 public static String[] getPreferencesValues(
316 PortletPreferences preferences, String key, String languageId) {
317
318 return getPreferencesValues(preferences, key, languageId, true);
319 }
320
321 public static String[] getPreferencesValues(
322 PortletPreferences preferences, String key, String languageId,
323 boolean useDefault) {
324
325 String localizedKey = _getPreferencesKey(key, languageId);
326
327 String[] values = preferences.getValues(localizedKey, new String[0]);
328
329 if (useDefault && Validator.isNull(values)) {
330 values = preferences.getValues(key, new String[0]);
331 }
332
333 return values;
334 }
335
336 public static String removeLocalization(
337 String xml, String key, String requestedLanguageId) {
338
339 return removeLocalization(xml, key, requestedLanguageId, false);
340 }
341
342 public static String removeLocalization(
343 String xml, String key, String requestedLanguageId, boolean cdata) {
344
345 if (Validator.isNull(xml)) {
346 return StringPool.BLANK;
347 }
348
349 xml = _sanitizeXML(xml);
350
351 String systemDefaultLanguageId = LocaleUtil.toLanguageId(
352 LocaleUtil.getDefault());
353
354 XMLStreamReader xmlStreamReader = null;
355 XMLStreamWriter xmlStreamWriter = null;
356
357 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
358
359 Thread currentThread = Thread.currentThread();
360
361 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
362
363 try {
364 if (contextClassLoader != portalClassLoader) {
365 currentThread.setContextClassLoader(portalClassLoader);
366 }
367
368 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
369
370 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
371 new UnsyncStringReader(xml));
372
373 String availableLocales = StringPool.BLANK;
374 String defaultLanguageId = StringPool.BLANK;
375
376
378 if (xmlStreamReader.hasNext()) {
379 xmlStreamReader.nextTag();
380
381 availableLocales = xmlStreamReader.getAttributeValue(
382 null, _AVAILABLE_LOCALES);
383 defaultLanguageId = xmlStreamReader.getAttributeValue(
384 null, _DEFAULT_LOCALE);
385
386 if (Validator.isNull(defaultLanguageId)) {
387 defaultLanguageId = systemDefaultLanguageId;
388 }
389 }
390
391 if ((availableLocales != null) &&
392 (availableLocales.indexOf(requestedLanguageId) != -1)) {
393
394 availableLocales = StringUtil.remove(
395 availableLocales, requestedLanguageId, StringPool.COMMA);
396
397 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter(
398 true);
399
400 XMLOutputFactory xmlOutputFactory =
401 XMLOutputFactory.newInstance();
402
403 xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
404 unsyncStringWriter);
405
406 xmlStreamWriter.writeStartDocument();
407 xmlStreamWriter.writeStartElement(_ROOT);
408 xmlStreamWriter.writeAttribute(
409 _AVAILABLE_LOCALES, availableLocales);
410 xmlStreamWriter.writeAttribute(
411 _DEFAULT_LOCALE, defaultLanguageId);
412
413 _copyNonExempt(
414 xmlStreamReader, xmlStreamWriter, requestedLanguageId,
415 defaultLanguageId, cdata);
416
417 xmlStreamWriter.writeEndElement();
418 xmlStreamWriter.writeEndDocument();
419
420 xmlStreamWriter.close();
421 xmlStreamWriter = null;
422
423 xml = unsyncStringWriter.toString();
424 }
425 }
426 catch (Exception e) {
427 if (_log.isWarnEnabled()) {
428 _log.warn(e, e);
429 }
430 }
431 finally {
432 if (contextClassLoader != portalClassLoader) {
433 currentThread.setContextClassLoader(contextClassLoader);
434 }
435
436 if (xmlStreamReader != null) {
437 try {
438 xmlStreamReader.close();
439 }
440 catch (Exception e) {
441 }
442 }
443
444 if (xmlStreamWriter != null) {
445 try {
446 xmlStreamWriter.close();
447 }
448 catch (Exception e) {
449 }
450 }
451 }
452
453 return xml;
454 }
455
456 public static void setLocalizedPreferencesValues (
457 ActionRequest actionRequest, PortletPreferences preferences,
458 String parameter)
459 throws Exception {
460
461 Map<Locale, String> map = getLocalizedParameter(
462 actionRequest, parameter);
463
464 for (Locale locale : map.keySet()) {
465 String languageId = LocaleUtil.toLanguageId(locale);
466
467 String key = parameter + StringPool.UNDERLINE + languageId;
468 String value = map.get(locale);
469
470 preferences.setValue(key, value);
471 }
472 }
473
474 public static void setPreferencesValue(
475 PortletPreferences preferences, String key, String languageId,
476 String value)
477 throws Exception {
478
479 preferences.setValue(_getPreferencesKey(key, languageId), value);
480 }
481
482 public static void setPreferencesValues(
483 PortletPreferences preferences, String key, String languageId,
484 String[] values)
485 throws Exception {
486
487 preferences.setValues(_getPreferencesKey(key, languageId), values);
488 }
489
490 public static String updateLocalization(
491 String xml, String key, String value) {
492
493 String defaultLanguageId = LocaleUtil.toLanguageId(
494 LocaleUtil.getDefault());
495
496 return updateLocalization(
497 xml, key, value, defaultLanguageId, defaultLanguageId);
498 }
499
500 public static String updateLocalization(
501 String xml, String key, String value, String requestedLanguageId) {
502
503 String defaultLanguageId = LocaleUtil.toLanguageId(
504 LocaleUtil.getDefault());
505
506 return updateLocalization(
507 xml, key, value, requestedLanguageId, defaultLanguageId);
508 }
509
510 public static String updateLocalization(
511 String xml, String key, String value, String requestedLanguageId,
512 String defaultLanguageId) {
513
514 return updateLocalization(
515 xml, key, value, requestedLanguageId, defaultLanguageId, false);
516 }
517
518 public static String updateLocalization(
519 String xml, String key, String value, String requestedLanguageId,
520 String defaultLanguageId, boolean cdata) {
521
522 xml = _sanitizeXML(xml);
523
524 XMLStreamReader xmlStreamReader = null;
525 XMLStreamWriter xmlStreamWriter = null;
526
527 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
528
529 Thread currentThread = Thread.currentThread();
530
531 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
532
533 try {
534 if (contextClassLoader != portalClassLoader) {
535 currentThread.setContextClassLoader(portalClassLoader);
536 }
537
538 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
539
540 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
541 new UnsyncStringReader(xml));
542
543 String availableLocales = StringPool.BLANK;
544
545
547 if (xmlStreamReader.hasNext()) {
548 xmlStreamReader.nextTag();
549
550 availableLocales = xmlStreamReader.getAttributeValue(
551 null, _AVAILABLE_LOCALES);
552
553 if (Validator.isNull(availableLocales)) {
554 availableLocales = defaultLanguageId;
555 }
556
557 if (availableLocales.indexOf(requestedLanguageId) == -1) {
558 availableLocales = StringUtil.add(
559 availableLocales, requestedLanguageId,
560 StringPool.COMMA);
561 }
562 }
563
564 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter(
565 true);
566
567 XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
568
569 xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
570 unsyncStringWriter);
571
572 xmlStreamWriter.writeStartDocument();
573 xmlStreamWriter.writeStartElement(_ROOT);
574 xmlStreamWriter.writeAttribute(
575 _AVAILABLE_LOCALES, availableLocales);
576 xmlStreamWriter.writeAttribute(_DEFAULT_LOCALE, defaultLanguageId);
577
578 _copyNonExempt(
579 xmlStreamReader, xmlStreamWriter, requestedLanguageId,
580 defaultLanguageId, cdata);
581
582 if (cdata) {
583 xmlStreamWriter.writeStartElement(key);
584 xmlStreamWriter.writeAttribute(
585 _LANGUAGE_ID, requestedLanguageId);
586 xmlStreamWriter.writeCData(value);
587 xmlStreamWriter.writeEndElement();
588 }
589 else {
590 xmlStreamWriter.writeStartElement(key);
591 xmlStreamWriter.writeAttribute(
592 _LANGUAGE_ID, requestedLanguageId);
593 xmlStreamWriter.writeCharacters(value);
594 xmlStreamWriter.writeEndElement();
595 }
596
597 xmlStreamWriter.writeEndElement();
598 xmlStreamWriter.writeEndDocument();
599
600 xmlStreamWriter.close();
601 xmlStreamWriter = null;
602
603 xml = unsyncStringWriter.toString();
604 }
605 catch (Exception e) {
606 if (_log.isWarnEnabled()) {
607 _log.warn(e, e);
608 }
609 }
610 finally {
611 if (contextClassLoader != portalClassLoader) {
612 currentThread.setContextClassLoader(contextClassLoader);
613 }
614
615 if (xmlStreamReader != null) {
616 try {
617 xmlStreamReader.close();
618 }
619 catch (Exception e) {
620 }
621 }
622
623 if (xmlStreamWriter != null) {
624 try {
625 xmlStreamWriter.close();
626 }
627 catch (Exception e) {
628 }
629 }
630 }
631
632 return xml;
633 }
634
635 private static void _copyNonExempt(
636 XMLStreamReader xmlStreamReader, XMLStreamWriter xmlStreamWriter,
637 String exemptLanguageId, String defaultLanguageId, boolean cdata)
638 throws XMLStreamException {
639
640 while (xmlStreamReader.hasNext()) {
641 int event = xmlStreamReader.next();
642
643 if (event == XMLStreamConstants.START_ELEMENT) {
644 String languageId = xmlStreamReader.getAttributeValue(
645 null, _LANGUAGE_ID);
646
647 if (Validator.isNull(languageId)) {
648 languageId = defaultLanguageId;
649 }
650
651 if (!languageId.equals(exemptLanguageId)) {
652 xmlStreamWriter.writeStartElement(
653 xmlStreamReader.getLocalName());
654 xmlStreamWriter.writeAttribute(_LANGUAGE_ID, languageId);
655
656 while (xmlStreamReader.hasNext()) {
657 event = xmlStreamReader.next();
658
659 if (event == XMLStreamConstants.CHARACTERS ||
660 event == XMLStreamConstants.CDATA) {
661
662 String text = xmlStreamReader.getText();
663
664 if (cdata) {
665 xmlStreamWriter.writeCData(text);
666 }
667 else {
668 xmlStreamWriter.writeCharacters(
669 xmlStreamReader.getText());
670 }
671
672 break;
673 }
674 else if (event == XMLStreamConstants.END_ELEMENT) {
675 break;
676 }
677 }
678
679 xmlStreamWriter.writeEndElement();
680 }
681 }
682 else if (event == XMLStreamConstants.END_DOCUMENT) {
683 break;
684 }
685 }
686 }
687
688 private static String _getCachedValue(
689 String xml, String requestedLanguageId, boolean useDefault) {
690
691 String value = null;
692
693 Map<Tuple, String> valueMap = _cache.get(xml);
694
695 if (valueMap != null) {
696 Tuple subkey = new Tuple(useDefault, requestedLanguageId);
697
698 value = valueMap.get(subkey);
699 }
700
701 return value;
702 }
703
704 private static String _getPreferencesKey(String key, String languageId) {
705 String defaultLanguageId = LocaleUtil.toLanguageId(
706 LocaleUtil.getDefault());
707
708 if (!languageId.equals(defaultLanguageId)) {
709 key += StringPool.UNDERLINE + languageId;
710 }
711
712 return key;
713 }
714
715 private static String _getRootAttribute(
716 String xml, String name, String defaultValue) {
717
718 String value = null;
719
720 XMLStreamReader xmlStreamReader = null;
721
722 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
723
724 Thread currentThread = Thread.currentThread();
725
726 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
727
728 try {
729 if (contextClassLoader != portalClassLoader) {
730 currentThread.setContextClassLoader(portalClassLoader);
731 }
732
733 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
734
735 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
736 new UnsyncStringReader(xml));
737
738 if (xmlStreamReader.hasNext()) {
739 xmlStreamReader.nextTag();
740
741 value = xmlStreamReader.getAttributeValue(null, name);
742 }
743 }
744 catch (Exception e) {
745 if (_log.isWarnEnabled()) {
746 _log.warn(e, e);
747 }
748 }
749 finally {
750 if (contextClassLoader != portalClassLoader) {
751 currentThread.setContextClassLoader(contextClassLoader);
752 }
753
754 if (xmlStreamReader != null) {
755 try {
756 xmlStreamReader.close();
757 }
758 catch (Exception e) {
759 }
760 }
761 }
762
763 if (Validator.isNull(value)) {
764 value = defaultValue;
765 }
766
767 return value;
768 }
769
770 private static String _sanitizeXML(String xml) {
771 if (Validator.isNull(xml) || (xml.indexOf("<root") == -1)) {
772 xml = _EMPTY_ROOT_NODE;
773 }
774
775 return xml;
776 }
777
778 private static void _setCachedValue(
779 String xml, String requestedLanguageId, boolean useDefault,
780 String value) {
781
782 if (Validator.isNotNull(xml) && !xml.equals(_EMPTY_ROOT_NODE)) {
783 synchronized (_cache) {
784 Map<Tuple, String> map = _cache.get(xml);
785
786 if (map == null) {
787 map = new HashMap<Tuple, String>();
788 }
789
790 Tuple subkey = new Tuple(useDefault, requestedLanguageId);
791
792 map.put(subkey, value);
793
794 _cache.put(xml, map);
795 }
796 }
797 }
798
799 private static final String _AVAILABLE_LOCALES = "available-locales";
800
801 private static final String _DEFAULT_LOCALE = "default-locale";
802
803 private static final String _EMPTY_ROOT_NODE = "<root />";
804
805 private static final String _LANGUAGE_ID = "language-id";
806
807 private static final String _ROOT = "root";
808
809 private static Log _log = LogFactoryUtil.getLog(LocalizationUtil.class);
810
811 private static Map<String, Map<Tuple, String>> _cache = new ReferenceMap(
812 ReferenceMap.SOFT, ReferenceMap.HARD);
813
814 }