1
14
15 package com.liferay.portal.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.Localization;
25 import com.liferay.portal.kernel.util.ParamUtil;
26 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
27 import com.liferay.portal.kernel.util.StringPool;
28 import com.liferay.portal.kernel.util.StringUtil;
29 import com.liferay.portal.kernel.util.Tuple;
30 import com.liferay.portal.kernel.util.Validator;
31
32 import java.util.HashMap;
33 import java.util.Locale;
34 import java.util.Map;
35
36 import javax.portlet.ActionRequest;
37 import javax.portlet.PortletPreferences;
38 import javax.portlet.PortletRequest;
39
40 import javax.xml.stream.XMLInputFactory;
41 import javax.xml.stream.XMLOutputFactory;
42 import javax.xml.stream.XMLStreamConstants;
43 import javax.xml.stream.XMLStreamException;
44 import javax.xml.stream.XMLStreamReader;
45 import javax.xml.stream.XMLStreamWriter;
46
47 import org.apache.commons.collections.map.ReferenceMap;
48
49
73 public class LocalizationImpl implements Localization {
74
75 public Object deserialize(JSONObject jsonObject) {
76 Locale[] locales = LanguageUtil.getAvailableLocales();
77
78 Map<Locale, String> map = new HashMap<Locale, String>();
79
80 for (Locale locale : locales) {
81 String languageId = LocaleUtil.toLanguageId(locale);
82
83 String value = jsonObject.getString(languageId);
84
85 if (Validator.isNotNull(value)) {
86 map.put(locale, value);
87 }
88 }
89
90 return map;
91 }
92
93 public String[] getAvailableLocales(String xml) {
94 String attributeValue = _getRootAttribute(
95 xml, _AVAILABLE_LOCALES, StringPool.BLANK);
96
97 return StringUtil.split(attributeValue);
98 }
99
100 public String getDefaultLocale(String xml) {
101 String defaultLanguageId = LocaleUtil.toLanguageId(
102 LocaleUtil.getDefault());
103
104 return _getRootAttribute(xml, _DEFAULT_LOCALE, defaultLanguageId);
105 }
106
107 public String getLocalization(String xml, String requestedLanguageId) {
108 return getLocalization(xml, requestedLanguageId, true);
109 }
110
111 public 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 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 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 Map<Locale, String> getLocalizedParameter(
289 PortletRequest portletRequest, String parameter) {
290
291 return getLocalizationMap(portletRequest, parameter);
292 }
293
294 public String getPreferencesValue(
295 PortletPreferences preferences, String key, String languageId) {
296
297 return getPreferencesValue(preferences, key, languageId, true);
298 }
299
300 public 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 String[] getPreferencesValues(
316 PortletPreferences preferences, String key, String languageId) {
317
318 return getPreferencesValues(preferences, key, languageId, true);
319 }
320
321 public 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 String removeLocalization(
337 String xml, String key, String requestedLanguageId) {
338
339 return removeLocalization(xml, key, requestedLanguageId, false);
340 }
341
342 public 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 =
398 new UnsyncStringWriter();
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 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 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 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 String updateLocalization(String xml, String key, String value) {
491 String defaultLanguageId = LocaleUtil.toLanguageId(
492 LocaleUtil.getDefault());
493
494 return updateLocalization(
495 xml, key, value, defaultLanguageId, defaultLanguageId);
496 }
497
498 public String updateLocalization(
499 String xml, String key, String value, String requestedLanguageId) {
500
501 String defaultLanguageId = LocaleUtil.toLanguageId(
502 LocaleUtil.getDefault());
503
504 return updateLocalization(
505 xml, key, value, requestedLanguageId, defaultLanguageId);
506 }
507
508 public String updateLocalization(
509 String xml, String key, String value, String requestedLanguageId,
510 String defaultLanguageId) {
511
512 return updateLocalization(
513 xml, key, value, requestedLanguageId, defaultLanguageId, false);
514 }
515
516 public String updateLocalization(
517 String xml, String key, String value, String requestedLanguageId,
518 String defaultLanguageId, boolean cdata) {
519
520 xml = _sanitizeXML(xml);
521
522 XMLStreamReader xmlStreamReader = null;
523 XMLStreamWriter xmlStreamWriter = null;
524
525 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
526
527 Thread currentThread = Thread.currentThread();
528
529 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
530
531 try {
532 if (contextClassLoader != portalClassLoader) {
533 currentThread.setContextClassLoader(portalClassLoader);
534 }
535
536 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
537
538 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
539 new UnsyncStringReader(xml));
540
541 String availableLocales = StringPool.BLANK;
542
543
545 if (xmlStreamReader.hasNext()) {
546 xmlStreamReader.nextTag();
547
548 availableLocales = xmlStreamReader.getAttributeValue(
549 null, _AVAILABLE_LOCALES);
550
551 if (Validator.isNull(availableLocales)) {
552 availableLocales = defaultLanguageId;
553 }
554
555 if (availableLocales.indexOf(requestedLanguageId) == -1) {
556 availableLocales = StringUtil.add(
557 availableLocales, requestedLanguageId,
558 StringPool.COMMA);
559 }
560 }
561
562 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
563
564 XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
565
566 xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(
567 unsyncStringWriter);
568
569 xmlStreamWriter.writeStartDocument();
570 xmlStreamWriter.writeStartElement(_ROOT);
571 xmlStreamWriter.writeAttribute(
572 _AVAILABLE_LOCALES, availableLocales);
573 xmlStreamWriter.writeAttribute(_DEFAULT_LOCALE, defaultLanguageId);
574
575 _copyNonExempt(
576 xmlStreamReader, xmlStreamWriter, requestedLanguageId,
577 defaultLanguageId, cdata);
578
579 if (cdata) {
580 xmlStreamWriter.writeStartElement(key);
581 xmlStreamWriter.writeAttribute(
582 _LANGUAGE_ID, requestedLanguageId);
583 xmlStreamWriter.writeCData(value);
584 xmlStreamWriter.writeEndElement();
585 }
586 else {
587 xmlStreamWriter.writeStartElement(key);
588 xmlStreamWriter.writeAttribute(
589 _LANGUAGE_ID, requestedLanguageId);
590 xmlStreamWriter.writeCharacters(value);
591 xmlStreamWriter.writeEndElement();
592 }
593
594 xmlStreamWriter.writeEndElement();
595 xmlStreamWriter.writeEndDocument();
596
597 xmlStreamWriter.close();
598 xmlStreamWriter = null;
599
600 xml = unsyncStringWriter.toString();
601 }
602 catch (Exception e) {
603 if (_log.isWarnEnabled()) {
604 _log.warn(e, e);
605 }
606 }
607 finally {
608 if (contextClassLoader != portalClassLoader) {
609 currentThread.setContextClassLoader(contextClassLoader);
610 }
611
612 if (xmlStreamReader != null) {
613 try {
614 xmlStreamReader.close();
615 }
616 catch (Exception e) {
617 }
618 }
619
620 if (xmlStreamWriter != null) {
621 try {
622 xmlStreamWriter.close();
623 }
624 catch (Exception e) {
625 }
626 }
627 }
628
629 return xml;
630 }
631
632 private void _copyNonExempt(
633 XMLStreamReader xmlStreamReader, XMLStreamWriter xmlStreamWriter,
634 String exemptLanguageId, String defaultLanguageId, boolean cdata)
635 throws XMLStreamException {
636
637 while (xmlStreamReader.hasNext()) {
638 int event = xmlStreamReader.next();
639
640 if (event == XMLStreamConstants.START_ELEMENT) {
641 String languageId = xmlStreamReader.getAttributeValue(
642 null, _LANGUAGE_ID);
643
644 if (Validator.isNull(languageId)) {
645 languageId = defaultLanguageId;
646 }
647
648 if (!languageId.equals(exemptLanguageId)) {
649 xmlStreamWriter.writeStartElement(
650 xmlStreamReader.getLocalName());
651 xmlStreamWriter.writeAttribute(_LANGUAGE_ID, languageId);
652
653 while (xmlStreamReader.hasNext()) {
654 event = xmlStreamReader.next();
655
656 if (event == XMLStreamConstants.CHARACTERS ||
657 event == XMLStreamConstants.CDATA) {
658
659 String text = xmlStreamReader.getText();
660
661 if (cdata) {
662 xmlStreamWriter.writeCData(text);
663 }
664 else {
665 xmlStreamWriter.writeCharacters(
666 xmlStreamReader.getText());
667 }
668
669 break;
670 }
671 else if (event == XMLStreamConstants.END_ELEMENT) {
672 break;
673 }
674 }
675
676 xmlStreamWriter.writeEndElement();
677 }
678 }
679 else if (event == XMLStreamConstants.END_DOCUMENT) {
680 break;
681 }
682 }
683 }
684
685 private String _getCachedValue(
686 String xml, String requestedLanguageId, boolean useDefault) {
687
688 String value = null;
689
690 Map<Tuple, String> valueMap = _cache.get(xml);
691
692 if (valueMap != null) {
693 Tuple subkey = new Tuple(useDefault, requestedLanguageId);
694
695 value = valueMap.get(subkey);
696 }
697
698 return value;
699 }
700
701 private String _getPreferencesKey(String key, String languageId) {
702 String defaultLanguageId = LocaleUtil.toLanguageId(
703 LocaleUtil.getDefault());
704
705 if (!languageId.equals(defaultLanguageId)) {
706 key += StringPool.UNDERLINE + languageId;
707 }
708
709 return key;
710 }
711
712 private String _getRootAttribute(
713 String xml, String name, String defaultValue) {
714
715 String value = null;
716
717 XMLStreamReader xmlStreamReader = null;
718
719 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
720
721 Thread currentThread = Thread.currentThread();
722
723 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
724
725 try {
726 if (contextClassLoader != portalClassLoader) {
727 currentThread.setContextClassLoader(portalClassLoader);
728 }
729
730 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
731
732 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
733 new UnsyncStringReader(xml));
734
735 if (xmlStreamReader.hasNext()) {
736 xmlStreamReader.nextTag();
737
738 value = xmlStreamReader.getAttributeValue(null, name);
739 }
740 }
741 catch (Exception e) {
742 if (_log.isWarnEnabled()) {
743 _log.warn(e, e);
744 }
745 }
746 finally {
747 if (contextClassLoader != portalClassLoader) {
748 currentThread.setContextClassLoader(contextClassLoader);
749 }
750
751 if (xmlStreamReader != null) {
752 try {
753 xmlStreamReader.close();
754 }
755 catch (Exception e) {
756 }
757 }
758 }
759
760 if (Validator.isNull(value)) {
761 value = defaultValue;
762 }
763
764 return value;
765 }
766
767 private String _sanitizeXML(String xml) {
768 if (Validator.isNull(xml) || (xml.indexOf("<root") == -1)) {
769 xml = _EMPTY_ROOT_NODE;
770 }
771
772 return xml;
773 }
774
775 private void _setCachedValue(
776 String xml, String requestedLanguageId, boolean useDefault,
777 String value) {
778
779 if (Validator.isNotNull(xml) && !xml.equals(_EMPTY_ROOT_NODE)) {
780 synchronized (_cache) {
781 Map<Tuple, String> map = _cache.get(xml);
782
783 if (map == null) {
784 map = new HashMap<Tuple, String>();
785 }
786
787 Tuple subkey = new Tuple(useDefault, requestedLanguageId);
788
789 map.put(subkey, value);
790
791 _cache.put(xml, map);
792 }
793 }
794 }
795
796 private static final String _AVAILABLE_LOCALES = "available-locales";
797
798 private static final String _DEFAULT_LOCALE = "default-locale";
799
800 private static final String _EMPTY_ROOT_NODE = "<root />";
801
802 private static final String _LANGUAGE_ID = "language-id";
803
804 private static final String _ROOT = "root";
805
806 private static Log _log = LogFactoryUtil.getLog(LocalizationImpl.class);
807
808 private Map<String, Map<Tuple, String>> _cache = new ReferenceMap(
809 ReferenceMap.SOFT, ReferenceMap.HARD);
810
811 }