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