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