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