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