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