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