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