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